Skip to content

Instantly share code, notes, and snippets.

@MaximKotliar
Created March 15, 2024 16:39
Show Gist options
  • Save MaximKotliar/baffca4e32dc5f5fc26f4929a6857232 to your computer and use it in GitHub Desktop.
Save MaximKotliar/baffca4e32dc5f5fc26f4929a6857232 to your computer and use it in GitHub Desktop.
Cross-process (distributed) lock.
/// Distributed lock based on file locking
final class DistributedLock: NSLocking {
enum Error: Swift.Error {
case failToAquireLock
}
private let fileURL: URL
private var fileDescriptor: Int32 = -1
init(sharedDirectory: URL, name: String) {
self.fileURL = sharedDirectory.appendingPathComponent("\(name).lock")
}
func tryLock() -> Bool {
fileDescriptor = open(fileURL.path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)
let lockResult = flock(fileDescriptor, LOCK_EX)
return lockResult == 0
}
func lock() {
guard tryLock() else {
assertionFailure("Failed to aquire file lock, this is not expected.")
return
}
}
func unlock() {
if fileDescriptor != -1 {
close(fileDescriptor)
fileDescriptor = -1
}
}
func withAsyncLock<T>(_ closure: @escaping (@escaping() -> Void) throws -> T) throws -> T {
guard tryLock() else {
throw Error.failToAquireLock
}
return try closure(unlock)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment