### Latency Configuration Examples Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Examples of configuring latency for event coalescing. ```swift // No latency - all events reported immediately (can be noisy) let stream = FolderContentMonitor.makeStream(url: url, latency: 0.0) // 1-second latency - coalesces rapid changes let stream = FolderContentMonitor.makeStream(url: url, latency: 1.0) ``` -------------------------------- ### Swift Package Manager Installation Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Add AsyncFileMonitor to your Package.swift dependencies. ```swift dependencies: [ .package(url: "https://github.com/yourusername/AsyncFileMonitor.git", from: "1.0.0") ] ``` -------------------------------- ### Multiple Paths Monitoring Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Monitor several directories simultaneously by providing an array of paths. ```swift let stream = FolderContentMonitor.makeStream(paths: [ "/Users/you/Documents", "/Users/you/Desktop", "/Users/you/Downloads" ]) for await event in stream { print("Change detected in: \(event.eventPath)") } ``` -------------------------------- ### Demo Command Line Tool - Example Output Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Example output from the CLI tool when monitoring file changes. ```text 🎯 Starting AsyncFileMonitor CLI 📁 Monitoring paths: • /Users/username/Documents 📡 Press Ctrl+C to stop monitoring [14:23:15.123] 📄 /Users/username/Documents/test.txt 🔄 isFile, modified 🆔 Event ID: 12345678 [14:23:15.456] 📄 /Users/username/Documents/newfile.txt 🔄 isFile, created 🆔 Event ID: 12345679 ``` -------------------------------- ### Basic File Monitoring Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Monitor a single directory using FolderContentMonitor. ```swift import AsyncFileMonitor // Monitor a single directory let stream = FolderContentMonitor.makeStream(url: URL(fileURLWithPath: "/Users/you/Documents")) for await event in stream { print("File changed: \(event.filename)") print("Path: \(event.eventPath)") print("Change type: \(event.change)") } ``` -------------------------------- ### Advanced Configuration with FolderContentMonitor Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Use FolderContentMonitor directly for advanced control over latency and quality of service. ```swift let monitor = FolderContentMonitor( url: URL(fileURLWithPath: "/Users/you/Documents"), latency: 0.5, // Wait 0.5 seconds to coalesce events qos: .userInitiated // Quality of service level ) let stream = await monitor.makeStream() for await event in stream { // Handle events with custom configuration await processEvent(event) } ``` -------------------------------- ### Before (RxFileMonitor) Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Example of using RxFileMonitor to monitor folder content changes. ```swift import RxFileMonitor import RxSwift let monitor = FolderContentMonitor(url: folderUrl) let disposeBag = DisposeBag() monitor.rx.folderContentChange .subscribe(onNext: { event in print("File changed: \(event.filename)") }) .disposed(by: disposeBag) // Stop monitoring disposeBag = DisposeBag() ``` -------------------------------- ### Migration from RxFileMonitor - Before Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Example of how file monitoring was done using RxFileMonitor. ```swift import RxFileMonitor import RxSwift let monitor = FolderContentMonitor(url: folderUrl) let disposeBag = DisposeBag() monitor.rx.folderContentChange .subscribe(onNext: { event in print("File changed: \(event.filename)") }) .disposed(by: disposeBag) ``` -------------------------------- ### Task-Based Monitoring Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Use Swift's structured concurrency to manage monitoring tasks and ensure proper resource management. ```swift let monitorTask = Task { let stream = FolderContentMonitor.makeStream(url: documentsURL) for await event in stream { await handleFileChange(event) } } // Stop monitoring when done defer { monitorTask.cancel() } ``` -------------------------------- ### Understanding Events and Change Types Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Iterate through events and check for specific change types like created, modified, removed, or if it's a directory. ```swift for await event in stream { if event.change.contains(.created) { print("File created: \(event.filename)") } if event.change.contains(.modified) { print("File modified: \(event.filename)") } if event.change.contains(.removed) { print("File removed: \(event.filename)") } if event.change.contains(.isDirectory) { print("Directory changed: \(event.filename)") } } ``` -------------------------------- ### Error Handling - Path Validation Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Verify that a path exists before attempting to monitor it. ```swift let path = "/path/to/monitor" let url = URL(fileURLWithPath: path) // Verify path exists before monitoring guard FileManager.default.fileExists(atPath: path) else { print("Path does not exist: \(path)") return } let stream = FolderContentMonitor.makeStream(url: url) ``` -------------------------------- ### Simple editors (direct writes) file event patterns Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md This example shows the file event pattern for simple editors using direct writes. ```text file.txt changed (isFile, modified, xattrsModified) ``` -------------------------------- ### Handling Edge Cases in Events Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Provides an example of handling unusual event combinations, such as a file being created and removed in rapid succession. ```swift for await event in stream { // File might be both created and removed in rapid succession if event.change.contains(.created) && event.change.contains(.removed) { // Temporary file that was cleaned up quickly continue } // Handle normal cases await processEvent(event) } ``` -------------------------------- ### Filtering Events Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/GettingStarted.md Filter events to focus on specific changes, like only file modifications, or to skip system files. ```swift // Only monitor file modifications (not directories) for await event in stream where event.change.contains(.isFile) && event.change.contains(.modified) { await processModifiedFile(event.url) } // Skip system files for await event in stream { guard !event.filename.hasPrefix(".") else { continue } await handleUserFile(event) } ``` -------------------------------- ### Migration from RxFileMonitor - After Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Example of how file monitoring is done using AsyncFileMonitor with modern Swift concurrency. ```swift import AsyncFileMonitor let eventStream = FolderContentMonitor.makeStream(url: folderUrl) for await event in eventStream { print("File changed: \(event.filename)") } ``` -------------------------------- ### Filtering Events Early Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md An example of applying filters as early as possible to reduce processing overhead, specifically for file modifications. ```swift for await event in stream where event.change.contains(.isFile) && event.change.contains(.modified) { // Only process file modifications await handleFileModification(event) } ``` -------------------------------- ### Combining Multiple Monitors (AsyncFileMonitor) - Option 1 Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Example of monitoring multiple paths with a single stream in AsyncFileMonitor. ```swift // Option 1: Monitor multiple paths with single stream let stream = FolderContentMonitor.makeStream(paths: [ documentsUrl.path, desktopUrl.path ]) for await event in stream { print("Change in: \(event.eventPath)") } ``` -------------------------------- ### Isolation Assertion Example Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Ordering Analysis.md An example of using dispatchPrecondition to verify code runs on the expected queue. ```swift dispatchPrecondition(condition: .onQueue(FileSystemEventExecutor.shared.underlyingQueue)) ``` -------------------------------- ### Combining Multiple Monitors (RxFileMonitor) Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Example of merging multiple RxFileMonitor streams using Observable.merge. ```swift let documentsMonitor = FolderContentMonitor(url: documentsUrl) let desktopMonitor = FolderContentMonitor(url: desktopUrl) Observable.merge([ documentsMonitor.rx.folderContentChange, desktopMonitor.rx.folderContentChange ]) .subscribe(onNext: { event in print("Change in: \(event.eventPath)") }) .disposed(by: disposeBag) ``` -------------------------------- ### Debouncing (RxFileMonitor) Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Example of debouncing file change events in RxFileMonitor. ```swift monitor.rx.folderContentChange .debounce(.milliseconds(500), scheduler: MainScheduler.instance) .subscribe(onNext: { event in processDebounced(event) }) .disposed(by: disposeBag) ``` -------------------------------- ### Error Handling (RxFileMonitor) Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Example of handling errors in RxFileMonitor subscriptions. ```swift monitor.rx.folderContentChange .subscribe( onNext: { event in processEvent(event) }, onError: { error in print("Monitor error: \(error)") } ) .disposed(by: disposeBag) ``` -------------------------------- ### Multiple Streams (AsyncFileMonitor) Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Example of handling multiple streams for UI updates and background processing with AsyncFileMonitor. ```swift // Create independent streams let uiStream = FolderContentMonitor.makeStream(url: folderUrl) let backgroundStream = FolderContentMonitor.makeStream(url: folderUrl) // UI updates Task { @MainActor in for await event in uiStream { updateUI(for: event) } } // Background processing Task.detached { for await event in backgroundStream { await processInBackground(event) } } ``` -------------------------------- ### Multiple Streams (RxFileMonitor) Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Example of handling multiple streams for UI updates and background processing with RxFileMonitor. ```swift // UI updates monitor.rx.folderContentChange .observeOn(MainScheduler.instance) .subscribe(onNext: { event in updateUI(for: event) }) .disposed(by: disposeBag) // Background processing monitor.rx.folderContentChange .observeOn(backgroundScheduler) .subscribe(onNext: { event in processInBackground(event) }) .disposed(by: disposeBag) ``` -------------------------------- ### TextEdit (atomic saves) file event patterns Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Different applications can generate different event patterns. This example shows the pattern for TextEdit's atomic saves. ```text texteditfile.txt changed (isFile, renamed, xattrsModified) texteditfile.txt changed (isFile, renamed, finderInfoModified, xattrsModified) texteditfile.txt.sb-56afa5c6-DmdqsL changed (isFile, renamed) texteditfile.txt changed (isFile, renamed, finderInfoModified, inodeMetaModified, xattrsModified) texteditfile.txt.sb-56afa5c6-DmdqsL changed (isFile, modified, removed, renamed, changeOwner) ``` -------------------------------- ### Error Handling (AsyncFileMonitor) Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Example of handling errors in AsyncFileMonitor using a do-catch block. ```swift do { let stream = FolderContentMonitor.makeStream(url: folderUrl) for await event in stream { await processEvent(event) } } catch { print("Monitor error: \(error)") } ``` -------------------------------- ### FSEventStream Callback Example Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/FSEventStream Ordering Findings.md A minimal FSEventStream callback function that demonstrates direct event collection, proving FSEventStream's inherent ordering. ```swift let fsEventCallback: FSEventStreamCallback = { (stream, contextInfo, numEvents, eventPaths, eventFlags, eventIDs) in let collector = Unmanaged.fromOpaque(contextInfo!).takeUnretainedValue() let paths = unsafeBitCast(eventPaths, to: NSArray.self) as! [String] for index in 0.. - Monitor file system changes in real-time swift run watch - Monitor multiple paths simultaneously swift run watch - Show CLI usage help ``` -------------------------------- ### Batching Related Events Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Illustrates how to group related events and process them in batches after a brief delay. ```swift var pendingEvents: [FolderContentChangeEvent] = [] for await event in stream { pendingEvents.append(event) // Process batch after brief delay try? await Task.sleep(nanoseconds: 100_000_000) // 0.1 seconds if !pendingEvents.isEmpty { await processBatch(pendingEvents) pendingEvents.removeAll() } } ``` -------------------------------- ### Demo Command Line Tool - Monitor a single directory Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Command to monitor a single directory using the CLI tool. ```bash swift run watch /Users/username/Documents ``` -------------------------------- ### Building and Testing - Clean Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Command to clean the project build artifacts. ```bash make clean ``` -------------------------------- ### Event Ordering Tests Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Quick Reference.md Commands to run specific event ordering tests for AsyncFileMonitor, including the main ordering test, baseline regression test, and high-stress test. ```bash # Run the main ordering test swift test --filter eventOrderingWithCoalescedEvents # Run baseline regression test swift test --filter demonstrateCorrectBehavior # Run high-stress test swift test --filter highStressOrderingTest ``` -------------------------------- ### Basic Usage Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/AsyncFileMonitor.md Monitor a directory and process events using async/await. ```swift import AsyncFileMonitor // Monitor a directory let eventStream = FolderContentMonitor.makeStream(url: URL(fileURLWithPath: "/path/to/monitor/")) // Use async/await to process events for await event in eventStream { print("File changed: \(event.filename) at \(event.eventPath)") print("Change type: \(event.change)") } ``` -------------------------------- ### Event Coalescing with Latency Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Demonstrates how to use the `latency` parameter to reduce event noise by coalescing frequent events. ```swift // High-frequency monitoring (noisy) let stream = FolderContentMonitor.makeStream(url: url, latency: 0.0) // Coalesced monitoring (cleaner) let stream = FolderContentMonitor.makeStream(url: url, latency: 0.5) ``` -------------------------------- ### Event Structure Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Iterates through file system events and prints details about each event. ```swift for await event in stream { print("Event ID: \(event.eventID)") print("Path: \(event.eventPath)") print("Filename: \(event.filename)") print("Changes: \(event.change)") } ``` -------------------------------- ### Debouncing with AsyncFileMonitor Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Demonstrates how to use AsyncFileMonitor with automatic debouncing provided by FSEvents and a manual debouncing approach. ```swift let stream = FolderContentMonitor.makeStream(url: folderUrl, latency: 0.5) for await event in stream { // Events are automatically coalesced by FSEvents await processDebounced(event) } // For custom debouncing: var lastEventTime = Date() let debounceInterval: TimeInterval = 0.5 for await event in stream { let now = Date() if now.timeIntervalSince(lastEventTime) >= debounceInterval { await processDebounced(event) lastEventTime = now } } ``` -------------------------------- ### Focus on User Files Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Filters out hidden files, system files, and common temporary file patterns to focus on user-relevant files. ```swift for await event in stream { let filename = event.filename // Skip hidden files and system files guard !filename.hasPrefix(".") else { continue } // Skip common temporary file patterns guard !filename.contains("~") else { continue } guard !filename.hasSuffix(".tmp") else { continue } // Process user files await processUserFile(event) } ``` -------------------------------- ### After (AsyncFileMonitor) - Basic Usage Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Basic usage of AsyncFileMonitor to monitor folder content changes using async/await. ```swift import AsyncFileMonitor let stream = FolderContentMonitor.makeStream(url: folderUrl) for await event in stream { print("File changed: \(event.filename)") } // Monitoring stops automatically when loop exits ``` -------------------------------- ### Architecture Overview Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Ordering Analysis.md The architecture shows the flow of events from FSEventStream to the consumer, highlighting the critical point for executor preference. ```text FSEventStream (C API) ↓ FSEventStreamCallback (dispatch queue) ↓ FileSystemEventStream (RAII wrapper) ↓ FolderContentMonitor (actor) ↓ [Task with executor preference - CRITICAL POINT] StreamRegistrar (actor) ↓ AsyncStream continuations ↓ Consumer ``` -------------------------------- ### Monitoring Multiple Paths Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/AsyncFileMonitor.md Monitor multiple directories concurrently. ```swift let eventStream = FolderContentMonitor.makeStream(paths: [ "/Users/you/Documents", "/Users/you/Desktop" ]) for await event in eventStream { print("Change in \(event.eventPath): \(event.change)") } ``` -------------------------------- ### Reproducing the Issue - Restore the original code Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Ordering Analysis.md Instructions to revert the code change and restore the executor preference. ```swift Task(executorPreference: FileSystemEventExecutor.shared) { ``` -------------------------------- ### Modern Swift 6 Synchronization with Mutex Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Direct AsyncStream Approach.md Demonstrates using Swift 6's Mutex for safe, type-checked synchronization. ```swift // Safe, type-checked synchronization continuations.withLock { dict[id] = continuation } ``` -------------------------------- ### Reproducing the Issue - Run the baseline test Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Ordering Analysis.md Command to run the baseline test after breaking the code, to observe the event reordering. ```bash swift test --filter demonstrateCorrectBehavior ``` -------------------------------- ### Event Flow Pipeline Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Reordering with Executor.md Illustrates the sequence of operations and transitions involved in the FSEventStream event delivery process, from the kernel boundary to async stream continuations. ```text FSEventStream (macOS kernel/userspace boundary) ↓ [Buffering & Coalescing] FSEventStreamCallback (dispatch queue callback) ↓ [Dispatch Queue Scheduling] FileSystemEventStream.forward() ↓ [Task Creation with Executor Preference] FolderContentMonitor.broadcast() ↓ [Actor hop] StreamRegistrar.yield() ↓ AsyncStream continuations ``` -------------------------------- ### Event Flow Diagram Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Direct AsyncStream Approach.md Visual representation of the event flow from FSEventStream to AsyncStream consumers. ```text FSEventStream (C API) ↓ C Callback Function ↓ MulticastAsyncStream.send() ↓ AsyncStream.Continuation.yield() ↓ Multiple AsyncStream consumers ``` -------------------------------- ### Track Content Modifications Only Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Focuses on events related to file creation, modification, or removal, while ignoring pure metadata changes. ```swift for await event in stream { // Only process substantial changes if event.change.contains(.created) || event.change.contains(.modified) || event.change.contains(.removed) { await processContentChange(event) } // Skip pure metadata changes if event.change.isSubset(of: [.finderInfoModified, .xattrsModified]) { continue } } ``` -------------------------------- ### After (AsyncFileMonitor) - Task-based Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Task-based usage of AsyncFileMonitor for monitoring folder content changes. ```swift import AsyncFileMonitor let monitorTask = Task { let stream = FolderContentMonitor.makeStream(url: folderUrl) for await event in stream { print("File changed: \(event.filename)") } } // Stop monitoring monitorTask.cancel() ``` -------------------------------- ### OrderedSubscriber Management with OrderedDictionary Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Direct AsyncStream Approach.md Illustrates the use of OrderedDictionary within MulticastAsyncStream for preserving subscriber registration order. ```swift private let continuations: Mutex.Continuation>> ``` -------------------------------- ### How Event Ordering Can Break - With Executor Preference Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Ordering Analysis.md Demonstrates a Task created with executor preference, showing how this maintains chronological event order. ```swift Task(executorPreference: FileSystemEventExecutor.shared) { // ✅ With executor preference await self.broadcast(folderContentChangeEvents: events) } ``` -------------------------------- ### Advanced Configuration Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/AsyncFileMonitor.md Configure stream latency and filter events. ```swift // Create a stream with custom configuration let eventStream = FolderContentMonitor.makeStream( url: URL(fileURLWithPath: "/Users/you/Documents"), latency: 0.5 // Coalesce rapid changes ) // Process file events with filtering for await event in eventStream { // Filter for file changes only guard event.change.contains(.isFile) else { continue } // Skip system files guard event.filename != ".DS_Store" else { continue } // Note: This line was corrected from the original to avoid a syntax error. print("Document changed: \(event.filename)") } ``` -------------------------------- ### Async Context Requirement Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Illustrates the necessity of an async context for using AsyncFileMonitor's stream. ```swift // ❌ Won't compile func setupMonitoring() { let stream = FolderContentMonitor.makeStream(url: url) // Cannot use 'for await' in non-async function } // ✅ Correct func setupMonitoring() async { let stream = FolderContentMonitor.makeStream(url: url) for await event in stream { // Handle event } } ``` -------------------------------- ### Monitor Specific File Types Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Filters events to only process files with specific extensions, such as document types. ```swift let documentExtensions = Set(["txt", "md", "pdf", "doc", "docx"]) for await event in stream where event.change.contains(.isFile) { let pathExtension = event.url.pathExtension.lowercased() if documentExtensions.contains(pathExtension) { await processDocument(event) } } ``` -------------------------------- ### Metadata Changes Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Identifies changes to file system metadata such as ownership, Finder info, inode metadata, and extended attributes. ```swift for await event in stream { if event.change.contains(.changeOwner) { print("Ownership changed: \(event.filename)") } if event.change.contains(.finderInfoModified) { print("Finder info changed: \(event.filename)") } if event.change.contains(.inodeMetaModified) { print("Inode metadata changed: \(event.filename)") } if event.change.contains(.xattrsModified) { print("Extended attributes changed: \(event.filename)") } } ``` -------------------------------- ### File Operations Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Detects specific file operations like creation, modification, removal, and renaming. ```swift for await event in stream { if event.change.contains(.created) { print("File created: \(event.filename)") } if event.change.contains(.modified) { print("File modified: \(event.filename)") } if event.change.contains(.removed) { print("File removed: \(event.filename)") } if event.change.contains(.renamed) { print("File renamed/moved: \(event.filename)") } } ``` -------------------------------- ### Multiple Concurrent Streams Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/AsyncFileMonitor.md Create multiple streams from a single monitor, sharing a single FSEventStream. ```swift let monitor = FolderContentMonitor(url: documentsURL) // Create streams in specific order let uiUpdateStream = monitor.makeStream() let backupStream = monitor.makeStream() let logStream = monitor.makeStream() // Events are delivered in registration order: // 1. uiUpdateStream receives event first // 2. backupStream receives event second // 3. logStream receives event third Task { for await event in uiUpdateStream { await updateUI(for: event) } } Task { for await event in backupStream { guard event.change.contains(.modified) else { continue } await backupFile(event.url) } } Task { for await event in logStream { logger.info("File changed: \(event.filename)") } } ``` -------------------------------- ### Task Creation with Executor Preference Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Reordering with Executor.md Swift code snippet demonstrating how Task creation is configured with executor preference to ensure serial execution on a specific executor. ```swift // Even with executor preference, Task creation itself is asynchronous Task(executorPreference: FileSystemEventExecutor.shared) { await self.broadcast(folderContentChangeEvents: events) } ``` -------------------------------- ### How Event Ordering Can Break - Without Executor Preference Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Ordering Analysis.md Demonstrates a Task created without executor preference, illustrating how race conditions can lead to out-of-order event delivery. ```swift Task { // ❌ No executor preference await self.broadcast(folderContentChangeEvents: events) } ``` -------------------------------- ### MulticastAsyncStream Send Method Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Direct AsyncStream Approach.md The implementation of the send method in MulticastAsyncStream, showing direct yielding to continuations. ```swift public final class MulticastAsyncStream: Sendable { private let continuations: Mutex.Continuation>> public func send(_ value: T) where T: Sendable { let currentContinuations = continuations.withLock { Array($0.values) // Snapshot for safe iteration } for c in currentContinuations { c.yield(value) // Direct yield to each continuation } } } ``` -------------------------------- ### Task Management for AsyncFileMonitor Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Shows proper task management for AsyncFileMonitor streams to prevent leaks and ensure cleanup. ```swift // ❌ Task may leak Task { let stream = FolderContentMonitor.makeStream(url: url) for await event in stream { /* ... */ } } // ✅ Proper task management let monitorTask = Task { let stream = FolderContentMonitor.makeStream(url: url) for await event in stream { /* ... */ } } // Clean up when done defer { monitorTask.cancel() } ``` -------------------------------- ### Running Race Condition Tests Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Tests/RaceConditionTests/README.md Commands to run all race condition tests or specific test files using the Swift Package Manager. ```bash # Run all race condition tests swift test --filter RaceConditionTests # Run specific test files swift test --filter 0_FSEventStreamBaseline swift test --filter 1_FSEventStreamRaceConditions swift test --filter 2_ActorExecutorCoordination swift test --filter 3_EventOrderingRegressions swift test --filter 4_DirectAsyncStream ``` -------------------------------- ### Reproducing the Issue - Break the code temporarily Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Ordering Analysis.md Instructions to temporarily modify the code to introduce the event reordering issue for testing purposes. ```swift // Change from: Task(executorPreference: FileSystemEventExecutor.shared) { // To: Task { ``` -------------------------------- ### Latency Configuration Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Control event coalescing with the `latency` parameter. A latency of 0.0 can produce too much noise when applications make multiple rapid changes to files. Experiment with slightly higher values (e.g., 0.1-1.0 seconds) to reduce noise. ```swift // No latency - all events reported immediately (can be noisy) let eventStream = FolderContentMonitor.makeStream(url: url, latency: 0.0) // 1-second latency - coalesces rapid changes let eventStream = FolderContentMonitor.makeStream(url: url, latency: 1.0) ``` -------------------------------- ### Event Ordering Protection Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Quick Reference.md This code snippet demonstrates the critical code location in `FolderContentMonitor.swift` that prevents an event reordering race condition by specifying an executor preference. The warning emphasizes the importance of never removing the `executorPreference` parameter. ```swift Task(executorPreference: FileSystemEventExecutor.shared) { await self.broadcast(folderContentChangeEvents: events) } ``` -------------------------------- ### 0️⃣ FSEventStream Baseline Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Tests/RaceConditionTests/README.md This test demonstrates the FSEventStream C API used correctly with proper thread safety. It serves as the gold standard baseline that proves FSEventStream can maintain perfect chronological ordering of file system events when implemented correctly. ```swift 0_FSEventStreamBaseline.swift ``` -------------------------------- ### Actor Isolation for UI Updates with AsyncFileMonitor Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/Migration.md Demonstrates how to ensure UI updates are performed on the main actor when processing events from AsyncFileMonitor. ```swift // ❌ May not be on main actor for await event in stream { updateUI(for: event) // Potential concurrency issue } // ✅ Ensure main actor for UI updates for await event in stream { await MainActor.run { updateUI(for: event) } } ``` -------------------------------- ### 2️⃣ Actor and Executor Coordination Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Tests/RaceConditionTests/README.md This test examines how the original AsyncFileMonitor implementation using actors and executors behaves under different load conditions and demonstrates that even with sophisticated actor isolation and custom executor coordination (using direct copies of the actual library code), the fundamental Swift concurrency scheduling limitations persist. ```swift 2_ActorExecutorCoordination.swift ``` -------------------------------- ### 4️⃣ Direct AsyncStream Approach Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Tests/RaceConditionTests/README.md This test explores a direct AsyncStream.Continuation approach that bypasses actors entirely, using a custom MulticastAsyncStream with OrderedDictionary for multicast event distribution and Swift 6 Mutex for thread safety. Surprisingly, this approach demonstrates **better ordering guarantees** than the actor/executor approach. ```swift 4_DirectAsyncStream.swift ``` -------------------------------- ### File Type Identification Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Sources/AsyncFileMonitor/Documentation.docc/UnderstandingEvents.md Checks the 'change' flags to identify the type of item that changed (file, directory, symlink, hardlink). ```swift for await event in stream { if event.change.contains(.isFile) { print("Regular file changed: \(event.filename)") } if event.change.contains(.isDirectory) { print("Directory changed: \(event.filename)") } if event.change.contains(.isSymlink) { print("Symbolic link changed: \(event.filename)") } if event.change.contains(.isHardlink) { print("Hard link changed: \(event.filename)") } } ``` -------------------------------- ### Task Creation Without Executor Preference Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Reordering with Executor.md Swift code snippet showing Task creation without specifying an executor preference, allowing it to run on any available thread. ```swift Task { // Can run on any thread await self.broadcast(folderContentChangeEvents: events) } ``` -------------------------------- ### Task-based Processing Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Process file events in a separate Task and cancel it when done. ```swift let eventStream = FolderContentMonitor.makeStream(url: folderURL) let monitorTask = Task { for await event in eventStream { // Process file events await handleFileChange(event) } } // Stop monitoring monitorTask.cancel() ``` -------------------------------- ### Filtering Events Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/README.md Filter events directly in the for-await loop based on change type and modification. ```swift let eventStream = FolderContentMonitor.makeStream(url: documentsURL) for await event in eventStream where event.change.contains(.isFile) && event.change.contains(.modified) { await processModifiedFile(event.url) } ``` -------------------------------- ### 3️⃣ Event Ordering Regressions Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Tests/RaceConditionTests/README.md This test focuses on the critical executor preference implementation that maintains event ordering in AsyncFileMonitor. It includes both automated verification and manual regression procedures. ```swift 3_EventOrderingRegressions.swift ``` -------------------------------- ### StrictlyOrderedMonitor Actor Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Reordering with Executor.md An actor that implements strict chronological ordering by buffering and sorting events. ```swift actor StrictlyOrderedMonitor { private var eventBuffer: [FSEventStreamEventId: FolderContentChangeEvent] = [: ] private var lastProcessedID: FSEventStreamEventId = 0 func handleEvents(_ events: [FolderContentChangeEvent]) async { // Buffer all events for event in events { eventBuffer[event.eventID] = event } // Process events in strict order while let nextEvent = eventBuffer[lastProcessedID + 1] { await processEvent(nextEvent) eventBuffer.removeValue(forKey: lastProcessedID + 1) lastProcessedID += 1 } } } ``` -------------------------------- ### Critical Code Location Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/docs/Event Ordering Analysis.md This code snippet highlights the critical line in FolderContentMonitor.swift where Task executor preference is applied to prevent event reordering. ```swift // CRITICAL: This executor preference prevents event reordering // See docs/Event Ordering Analysis.md (20250904T080826) Task(executorPreference: FileSystemEventExecutor.shared) { await self.broadcast(folderContentChangeEvents: events) } ``` -------------------------------- ### 1️⃣ FSEventStream Race Conditions Source: https://github.com/cleancocoa/asyncfilemonitor/blob/main/Tests/RaceConditionTests/README.md This test deliberately removes thread safety from the FSEventStream implementation to demonstrate the catastrophic effects of race conditions. The unsafe implementation shows real-world consequences of concurrent programming mistakes. ```swift 1_FSEventStreamRaceConditions.swift ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.