Azure Files and filesystem change notification
Microsoft documentation reagarding how Azure Files handles FSN on SMB shares is bit vague. So I ran (AI generated) custom test suite, results below.
Azure Files SMB CHANGE_NOTIFY Test Report
Summary
This test verified that Azure Files SMB sends file change notifications between separate SMB clients.
One Windows Server 2025 VM wrote files to an Azure Files share. A second Windows Server 2025 VM had the same share mounted and monitored it with System.IO.FileSystemWatcher, which uses Windows ReadDirectoryChangesW.
Changes made by the writer were seen by the watcher without polling the directory tree. All tests that were run passed. A separate randomized stress test also passed with 10,000 of 10,000 expected notifications observed, with no missing events, watcher errors, or buffer overflows.
Test setup
The test ran in Azure Sweden Central with two Windows Server 2025 Azure Edition VMs.
afn-write (Windows Server 2025 Azure Edition, Standard_D4as_v6)
|
| SMB 3.1.1
v
Azure Files (StorageV2 / Standard_LRS, TransactionOptimized)
|
| SMB CHANGE_NOTIFY
v
afn-watch (Windows Server 2025 Azure Edition, Standard_D4as_v6)
|
| SMB 3.1.1
v
System.IO.FileSystemWatcherBoth machines accessed Azure Files share over SMB 3.1.1 using the storage account shared key. The storage account used its public endpoint, restricted to the lab VNet subnet.
afn-watch kept an active FileSystemWatcher on the share. afn-write changed files and directories through its own SMB session.
The tested path was therefore:
Writer SMB client
|
v
Azure Files
|
SMB CHANGE_NOTIFY
|
v
Watcher SMB client
|
ReadDirectoryChangesW
|
FileSystemWatcher
Functional test results
| Case | Fixture | Status | Expected | Observed | Missing | Watcher errors | Overflow | Duration ms | p50 ms | p95 ms | Max ms |
|---|---|---|---|---|---|---|---|---|---|---|---|
| T01 | file_create | pass | 1 | 1 | 0 | 0 | 0 | 18.544 | 29.887 | 29.887 | 29.887 |
| T02 | file_modify | pass | 1 | 1 | 0 | 0 | 0 | 30.568 | 22.005 | 22.005 | 22.005 |
| T03 | file_rename | pass | 1 | 1 | 0 | 0 | 0 | 36.661 | 62.694 | 62.694 | 62.694 |
| T04 | file_delete | pass | 1 | 1 | 0 | 0 | 0 | 17.435 | 68.843 | 68.843 | 68.843 |
| T05 | dir_create | pass | 1 | 1 | 0 | 0 | 0 | 25.034 | 39.688 | 39.688 | 39.688 |
| T06 | dir_rename | pass | 1 | 1 | 0 | 0 | 0 | 43.844 | 54.899 | 54.899 | 54.899 |
| T07 | dir_delete | pass | 1 | 1 | 0 | 0 | 0 | 48.818 | 64.710 | 64.710 | 64.710 |
| T08 | recreate | pass | 2 | 2 | 0 | 0 | 0 | 37.336 | 23.906 | 37.795 | 37.795 |
| T09 | atomic_replace | pass | 1 | 1 | 0 | 0 | 0 | 33.907 | 33.325 | 33.325 | 33.325 |
| T10 | burst100 | pass | 100 | 100 | 0 | 0 | 0 | 1730.884 | 49.787 | 68.683 | 76.076 |
The 100-file burst produced all 100 expected Created events. Each file also produced a Changed event, and creating the test directory produced one additional Created event.
The raw event stream for that test contained 201 callbacks:
100 × file Created
100 × file Changed
1 × test directory Created
None of the required Created notifications were missing.
10,000-operation stress test
A separate randomized stress run was performed with 10,000 filesystem mutations.
10,000 / 10,000 expected notifications observed
0 missing notifications
0 watcher
Errorevents0 buffer overflows
39.90 operations/s
250.65 seconds total writer time
p50 latency: 50.2 ms
p95 latency: 71.6 ms
maximum latency: 168.9 ms
The run included file and directory creation, modification, rename and deletion, as well as 1,000 atomic file replacements.
Results by operation type
| Operation | Expected | Observed | Missing | Missing rate | p50 ms | p95 ms | Max ms |
|---|---|---|---|---|---|---|---|
| create_file | 1750 | 1750 | 0 | 0.00% | 50.956 | 73.070 | 153.856 |
| delete_file | 1650 | 1650 | 0 | 0.00% | 48.788 | 69.032 | 86.020 |
| modify_file | 1100 | 1100 | 0 | 0.00% | 50.454 | 71.149 | 88.097 |
| rename_file | 1100 | 1100 | 0 | 0.00% | 47.469 | 68.528 | 82.597 |
| create_dir | 1200 | 1200 | 0 | 0.00% | 51.789 | 72.774 | 88.117 |
| rename_dir | 1100 | 1100 | 0 | 0.00% | 52.461 | 74.720 | 168.936 |
| delete_dir | 1100 | 1100 | 0 | 0.00% | 48.854 | 70.790 | 92.013 |
| replace_file | 1000 | 1000 | 0 | 0.00% | 50.947 | 70.819 | 83.900 |
Results by expected signal
| Expected signal | Expected operations | Observed | Missing |
|---|---|---|---|
| Created | 2950 | 2950 | 0 |
| Changed | 1100 | 1100 | 0 |
| Deleted | 2750 | 2750 | 0 |
| RenamedOrPair | 2200 | 2200 | 0 |
| ReplaceTarget | 1000 | 1000 | 0 |
The watcher produced 5,860 additional callbacks beyond the required notifications. These were mainly Changed events caused by file writes and events related to temporary files used during atomic replacements.
They did not replace or mask required events: all 10,000 expected signals were matched separately.
| Event type | Matched callbacks | Extra callbacks |
|---|---|---|
| Changed | 2100 | 3850 |
| Created | 2950 | 1010 |
| Deleted | 2750 | 1000 |
| Renamed | 2200 | 0 |
No watcher Error callbacks were recorded during the stress run.
Conclusion
Azure Files SMB delivered file and directory change notifications from one SMB client to another client's active ReadDirectoryChangesW / FileSystemWatcher subscription.
The behavior was confirmed for:
file create, modify, rename and delete
directory create, rename and delete
rapid delete and recreate
atomic file replacement
a 100-file burst
a randomized 10,000-operation workload
In the 10,000-operation stress run, Azure Files delivered every expected cross-client notification at roughly 40 filesystem mutations per second. No events were lost, no watcher errors occurred, and no watcher buffer overflow was observed. Notification latency remained in the tens-of-milliseconds range, with a p95 of 71.6 ms and a maximum of 168.9 ms.
Comments
Post a Comment
Got something to say?!