Integrate transaction handling utility part 2

pull/213/head
nielsandriesse 5 years ago
parent e9fc5b748e
commit a42b6afce8

@ -112,7 +112,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
* We don't want to delete the session. Ref: SignalServiceKit/Loki/Docs/SessionReset.md
* ================
if firstAttempt {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
Logger.info("deleting sessions for recipient: \(self.recipientId)")
self.primaryStorage.deleteAllSessions(forContact: self.recipientId, protocolContext: transaction)
}
@ -127,7 +127,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
return self.messageSender.sendPromise(message: endSessionMessage)
}.done {
Logger.info("successfully sent EndSessionMessage.")
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
// Archive the just-created session since the recipient should delete their corresponding
// session upon receiving and decrypting our EndSession message.
// Otherwise if we send another message before them, they wont have the session to decrypt it.
@ -160,7 +160,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
}
override public func didSucceed() {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
self.durableOperationDelegate?.durableOperationDidSucceed(self, transaction: transaction)
}
}
@ -168,7 +168,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
override public func didReportError(_ error: Error) {
Logger.debug("remainingRetries: \(self.remainingRetries)")
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
self.durableOperationDelegate?.durableOperation(self, didReportError: error, transaction: transaction)
}
}
@ -192,7 +192,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
override public func didFail(error: Error) {
Logger.error("failed to send EndSessionMessage with error: \(error.localizedDescription)")
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
self.durableOperationDelegate?.durableOperation(self, didFailWithError: error, transaction: transaction)
// Even though this is the failure handler - which means probably the recipient didn't receive the message

@ -180,7 +180,7 @@ final class ConversationTitleView : UIView {
if thread.groupModel.groupType == .closedGroup {
userCount = GroupUtilities.getClosedGroupMemberCount(thread)
} else if thread.groupModel.groupType == .openGroup {
storage.dbReadConnection.readWrite { transaction in
storage.dbReadConnection.read { transaction in
if let publicChat = LokiDatabaseUtilities.getPublicChat(for: self.thread.uniqueId!, in: transaction) {
userCount = storage.getUserCount(for: publicChat, in: transaction)
}

@ -63,7 +63,7 @@ public final class LokiRSSFeedPoller : NSObject {
envelope.setSource(NSLocalizedString("Loki", comment: ""))
envelope.setSourceDevice(OWSDevicePrimaryDeviceId)
envelope.setContent(try! content.build().serializedData())
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction, serverID: 0)
}
}

@ -186,7 +186,7 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate {
SSKEnvironment.shared.messageSender.send(linkingAuthorizationMessage, success: {
let storage = OWSPrimaryStorage.shared()
let slaveHexEncodedPublicKey = deviceLink.slave.hexEncodedPublicKey
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
let thread = TSContactThread.getOrCreateThread(withContactId: slaveHexEncodedPublicKey, transaction: transaction)
thread.save(with: transaction)
}
@ -196,7 +196,7 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate {
let _ = SSKEnvironment.shared.syncManager.syncAllContacts()
}
let _ = SSKEnvironment.shared.syncManager.syncAllOpenGroups()
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.setFriendRequestStatus(.friends, for: slaveHexEncodedPublicKey, transaction: transaction)
}
DispatchQueue.main.async {
@ -251,7 +251,7 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate {
session.markLinkingRequestAsProcessed() // Only relevant in master mode
delegate?.handleDeviceLinkingModalDismissed() // Only relevant in slave mode
if let deviceLink = deviceLink {
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
OWSPrimaryStorage.shared().removePreKeyBundle(forContact: deviceLink.slave.hexEncodedPublicKey, transaction: transaction)
}
}

@ -146,14 +146,14 @@ final class DeviceLinksVC : BaseVC, UITableViewDataSource, UITableViewDelegate,
let unlinkDeviceMessage = UnlinkDeviceMessage(thread: thread)
SSKEnvironment.shared.messageSender.send(unlinkDeviceMessage, success: {
let storage = OWSPrimaryStorage.shared()
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.removePreKeyBundle(forContact: linkedDeviceHexEncodedPublicKey, transaction: transaction)
storage.deleteAllSessions(forContact: linkedDeviceHexEncodedPublicKey, protocolContext: transaction)
}
}, failure: { _ in
print("[Loki] Failed to send unlink device message.")
let storage = OWSPrimaryStorage.shared()
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.removePreKeyBundle(forContact: linkedDeviceHexEncodedPublicKey, transaction: transaction)
storage.deleteAllSessions(forContact: linkedDeviceHexEncodedPublicKey, protocolContext: transaction)
}

@ -369,7 +369,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol
let alert = UIAlertController(title: NSLocalizedString("CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE", comment: ""), message: NSLocalizedString("CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE", comment: ""), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("TXT_DELETE_TITLE", comment: ""), style: .destructive) { _ in
guard let self = self else { return }
self.editingDatabaseConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
if let publicChat = publicChat {
var messageIDs: Set<String> = []
thread.enumerateInteractions(with: transaction) { interaction, _ in

@ -135,7 +135,7 @@ final class JoinPublicChatVC : BaseVC, UIPageViewControllerDataSource, UIPageVie
let urlAsString = url.absoluteString
let displayName = OWSProfileManager.shared().localProfileName()
// TODO: Profile picture & profile key
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
transaction.removeObject(forKey: "\(urlAsString).\(channelID)", inCollection: LokiPublicChatAPI.lastMessageServerIDCollection)
transaction.removeObject(forKey: "\(urlAsString).\(channelID)", inCollection: LokiPublicChatAPI.lastDeletionServerIDCollection)
}

@ -158,7 +158,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat
let userHexEncodedPublicKey = getUserHexEncodedPublicKey()
let storage = OWSPrimaryStorage.shared()
var masterHexEncodedPublicKey = ""
storage.dbReadConnection.readWrite { transaction in
storage.dbReadConnection.read { transaction in
masterHexEncodedPublicKey = storage.getMasterHexEncodedPublicKey(for: userHexEncodedPublicKey, in: transaction) ?? userHexEncodedPublicKey
}
let members = selectedContacts + [ masterHexEncodedPublicKey ]

@ -659,7 +659,7 @@ class NotificationActionHandler {
}
private func markAsRead(thread: TSThread) -> Promise<Void> {
return dbConnection.readWritePromise { transaction in
return Storage.write { transaction in
thread.markAllAsRead(with: transaction)
}
}

@ -889,7 +889,7 @@ public class ExperienceUpgradesPageViewController: OWSViewController, UIPageView
@objc public override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
// Blocking write before dismiss, to be sure they're marked as complete
// before HomeView.didAppear is re-fired.
self.editingDBConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
Logger.info("marking all upgrades as seen.")
ExperienceUpgradeFinder.shared.markAllAsSeen(transaction: transaction)
}

@ -19,7 +19,7 @@ public class LK001UpdateFriendRequestStatusStorage : OWSDatabaseMigration {
private func doMigrationAsync(completion: @escaping OWSDatabaseMigrationCompletion) {
DispatchQueue.global().async {
self.dbReadWriteConnection().readWrite { transaction in
try! Storage.writeSync { transaction in
var threads: [TSContactThread] = []
TSContactThread.enumerateCollectionObjects(with: transaction) { object, _ in
guard let thread = object as? TSContactThread else { return }

@ -25,7 +25,7 @@ public class OWS110SortIdMigration: OWSDatabaseMigration {
private func doMigration(completion: @escaping OWSDatabaseMigrationCompletion) {
// TODO batch this?
self.dbReadWriteConnection().readWrite { transaction in
try! Storage.writeSync { transaction in
var archivedThreads: [TSThread] = []

@ -35,7 +35,7 @@ public class OWS111UDAttributesMigration: OWSDatabaseMigration {
private func doMigration() {
tsAccountManager.updateAccountAttributes().retainUntilComplete()
self.dbReadWriteConnection().readWrite { transaction in
try! Storage.writeSync { transaction in
self.save(with: transaction)
}
}

@ -39,7 +39,7 @@ public class OWS112TypingIndicatorsMigration: OWSDatabaseMigration {
self.typingIndicators.setTypingIndicatorsEnabled(value: false)
DispatchQueue.global().async {
self.dbReadWriteConnection().readWrite { transaction in
try! Storage.writeSync { transaction in
self.save(with: transaction)
}

@ -53,7 +53,7 @@ public class OWS113MultiAttachmentMediaMessages: OWSDatabaseMigration {
}
}
}
self.dbReadWriteConnection().readWrite { transaction in
try! Storage.writeSync { transaction in
for (attachmentId, messageId) in legacyAttachments {
autoreleasepool {
guard let attachment = TSAttachment.fetch(uniqueId: attachmentId, transaction: transaction) else {

@ -30,7 +30,7 @@ public class OWS114RemoveDynamicInteractions: OWSDatabaseMigration {
private func doMigrationAsync(completion : @escaping OWSDatabaseMigrationCompletion) {
DispatchQueue.global().async {
self.dbReadWriteConnection().readWrite { transaction in
try! Storage.writeSync { transaction in
guard let dbView = TSDatabaseView.threadSpecialMessagesDatabaseView(transaction) as? YapDatabaseViewTransaction else {
owsFailDebug("Couldn't load db view.")
return

@ -53,7 +53,7 @@ public extension LokiAPI {
}
}.done(on: DispatchQueue.global()) { snode in
seal.fulfill(snode)
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
print("[Loki] Persisting snode pool to database.")
storage.setSnodePool(LokiAPI.snodePool, in: transaction)
}
@ -87,7 +87,7 @@ public extension LokiAPI {
parseTargets(from: $0)
}.get { swarm in
swarmCache[hexEncodedPublicKey] = swarm
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.setSwarm(swarm, for: hexEncodedPublicKey, in: transaction)
}
}
@ -101,7 +101,7 @@ public extension LokiAPI {
internal static func dropSnodeFromSnodePool(_ target: LokiAPITarget) {
LokiAPI.snodePool.remove(target)
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.dropSnodeFromSnodePool(target, in: transaction)
}
}
@ -111,7 +111,7 @@ public extension LokiAPI {
if var swarm = swarm, let index = swarm.firstIndex(of: target) {
swarm.remove(at: index)
LokiAPI.swarmCache[hexEncodedPublicKey] = swarm
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.setSwarm(swarm, for: hexEncodedPublicKey, in: transaction)
}
}
@ -120,7 +120,7 @@ public extension LokiAPI {
// MARK: Public API
@objc public static func clearSnodePool() {
snodePool.removeAll()
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.clearSnodePool(in: transaction)
}
}

@ -194,14 +194,14 @@ public final class LokiAPI : NSObject {
var result: String? = nil
// Uses a read/write connection because getting the last message hash value also removes expired messages as needed
// TODO: This shouldn't be the case; a getter shouldn't have an unexpected side effect
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
result = storage.getLastMessageHash(forSnode: target.address, transaction: transaction)
}
return result
}
private static func setLastMessageHashValue(for target: LokiAPITarget, hashValue: String, expirationDate: UInt64) {
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.setLastMessageHash(forSnode: target.address, hash: hashValue, expiresAt: expirationDate, transaction: transaction)
}
}
@ -218,7 +218,7 @@ public final class LokiAPI : NSObject {
}
private static func setReceivedMessageHashValues(to receivedMessageHashValues: Set<String>) {
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
transaction.setObject(receivedMessageHashValues, forKey: receivedMessageHashValuesKey, inCollection: receivedMessageHashValuesCollection)
}
}

@ -38,7 +38,7 @@ public class LokiDotNetAPI : NSObject {
return Promise.value(token)
} else {
return requestNewAuthToken(for: server).then(on: DispatchQueue.global()) { submitAuthToken($0, for: server) }.map(on: DispatchQueue.global()) { token in
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
setAuthToken(for: server, to: token, in: transaction)
}
return token
@ -51,7 +51,7 @@ public class LokiDotNetAPI : NSObject {
}
public static func clearAuthToken(for server: String) {
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
transaction.removeObject(forKey: server, inCollection: authTokenCollection)
}
}

@ -123,7 +123,7 @@ public enum OnionRequestAPI {
}
}.map(on: LokiAPI.workQueue) { paths in
OnionRequestAPI.paths = paths
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
print("[Loki] Persisting onion request paths to database.")
OWSPrimaryStorage.shared().setOnionRequestPaths(paths, in: transaction)
}
@ -163,7 +163,7 @@ public enum OnionRequestAPI {
private static func dropAllPaths() {
paths.removeAll()
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
OWSPrimaryStorage.shared().clearOnionRequestPaths(in: transaction)
}
}

@ -37,13 +37,13 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
}
private static func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64) {
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
transaction.setObject(newValue, forKey: "\(server).\(group)", inCollection: lastMessageServerIDCollection)
}
}
private static func removeLastMessageServerID(for group: UInt64, on server: String) {
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
transaction.removeObject(forKey: "\(server).\(group)", inCollection: lastMessageServerIDCollection)
}
}
@ -57,13 +57,13 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
}
private static func setLastDeletionServerID(for group: UInt64, on server: String, to newValue: UInt64) {
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
transaction.setObject(newValue, forKey: "\(server).\(group)", inCollection: lastDeletionServerIDCollection)
}
}
private static func removeLastDeletionServerID(for group: UInt64, on server: String) {
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
transaction.removeObject(forKey: "\(server).\(group)", inCollection: lastDeletionServerIDCollection)
}
}
@ -271,7 +271,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
print("[Loki] Couldn't parse display names for users: \(hexEncodedPublicKeys) from: \(rawResponse).")
throw LokiDotNetAPIError.parsingFailed
}
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
data.forEach { data in
guard let user = data["user"] as? JSON, let hexEncodedPublicKey = user["username"] as? String, let rawDisplayName = user["name"] as? String else { return }
let endIndex = hexEncodedPublicKey.endIndex
@ -355,7 +355,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
throw LokiDotNetAPIError.parsingFailed
}
let storage = OWSPrimaryStorage.shared()
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
storage.setUserCount(memberCount, forPublicChatWithID: "\(server).\(channel)", in: transaction)
}
// TODO: Use this to update open group names as needed

@ -71,7 +71,7 @@ public final class LokiPublicChatManager : NSObject {
let model = TSGroupModel(title: chat.displayName, memberIds: [userHexEncodedPublicKey!, chat.server], image: nil, groupId: LKGroupUtilities.getEncodedOpenGroupIDAsData(chat.id), groupType: .openGroup, adminIds: [])
// Store the group chat mapping
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
let thread = TSGroupThread.getOrCreateThread(with: model, transaction: transaction)
// Save the group chat
@ -118,7 +118,7 @@ public final class LokiPublicChatManager : NSObject {
}
// Remove the chat from the db
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
LokiDatabaseUtilities.removePublicChat(for: threadId, in: transaction)
}

@ -163,7 +163,7 @@ public final class LokiPublicChatPoller : NSObject {
envelope.setSource(senderHexEncodedPublicKey)
envelope.setSourceDevice(OWSDevicePrimaryDeviceId)
envelope.setContent(try! content.build().serializedData())
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
transaction.setObject(senderDisplayName, forKey: senderHexEncodedPublicKey, inCollection: publicChat.id)
let messageServerID = message.serverID
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction, serverID: messageServerID ?? 0)
@ -213,7 +213,7 @@ public final class LokiPublicChatPoller : NSObject {
private func pollForDeletedMessages() {
let publicChat = self.publicChat
let _ = LokiPublicChatAPI.getDeletedMessageServerIDs(for: publicChat.channel, on: publicChat.server).done(on: DispatchQueue.global()) { deletedMessageServerIDs in
try! Storage.syncWrite { transaction in
try! Storage.writeSync { transaction in
let deletedMessageIDs = deletedMessageServerIDs.compactMap { OWSPrimaryStorage.shared().getIDForMessage(withServerID: UInt($0), in: transaction) }
deletedMessageIDs.forEach { messageID in
TSMessage.fetch(uniqueId: messageID)?.remove(with: transaction)

@ -47,13 +47,13 @@ public final class Storage : NSObject {
}
/// Blocks the calling thread until the write has finished.
@objc(syncWriteWithBlock:error:)
public static func objc_syncWrite(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) throws {
try syncWrite(with: block)
@objc(writeSyncWithBlock:error:)
public static func objc_writeSync(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) throws {
try writeSync(with: block)
}
/// Blocks the calling thread until the write has finished.
public static func syncWrite(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) throws {
public static func writeSync(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) throws {
try write(with: block).wait()
}
}

@ -66,7 +66,7 @@ public final class FriendRequestExpirationJob : NSObject {
expireMessages()
var nextExpirationTimestamp: UInt64? = nil
databaseConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
nextExpirationTimestamp = self.messageFinder.nextExpirationTimestamp(with: transaction)
}
@ -108,7 +108,7 @@ public final class FriendRequestExpirationJob : NSObject {
guard let strongSelf = self else { return }
strongSelf.databaseConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
strongSelf.messageFinder.enumurateMessagesPendingExpiration(with: { message in
guard message.thread is TSContactThread else { return }

@ -241,7 +241,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
}
}
dbConnection.readWrite { (transaction) in
try! Storage.writeSync { (transaction) in
let oldMode = self.unidentifiedAccessMode(forRecipientId: recipientId, isLocalNumber: isLocalNumber, transaction: transaction)
transaction.setObject(mode.rawValue as Int, forKey: recipientId, inCollection: self.kUnidentifiedAccessCollection)

@ -51,11 +51,11 @@ public class MessageSenderJobQueue: NSObject, JobQueue {
inMessage: mediaMessage,
completionHandler: { error in
if let error = error {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
mediaMessage.update(sendingError: error, transaction: transaction)
}
} else {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
self.add(message: mediaMessage, removeMessageAfterSending: isTemporaryAttachment, transaction: transaction)
}
}
@ -96,7 +96,7 @@ public class MessageSenderJobQueue: NSObject, JobQueue {
/// Used when the user clears their database to cancel any outstanding jobs.
@objc public func clearAllJobs() {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
let statuses: [SSKJobRecordStatus] = [ .unknown, .ready, .running, .permanentlyFailed ]
var records: [SSKJobRecord] = []
statuses.forEach {
@ -196,7 +196,7 @@ public class MessageSenderOperation: OWSOperation, DurableOperation {
}
override public func didSucceed() {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
self.durableOperationDelegate?.durableOperationDidSucceed(self, transaction: transaction)
if self.jobRecord.removeMessageAfterSending {
self.message.remove(with: transaction)
@ -205,7 +205,7 @@ public class MessageSenderOperation: OWSOperation, DurableOperation {
}
override public func didReportError(_ error: Error) {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
self.durableOperationDelegate?.durableOperation(self, didReportError: error, transaction: transaction)
}
}
@ -227,7 +227,7 @@ public class MessageSenderOperation: OWSOperation, DurableOperation {
}
override public func didFail(error: Error) {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
self.durableOperationDelegate?.durableOperation(self, didFailWithError: error, transaction: transaction)
self.message.update(sendingError: error, transaction: transaction)

@ -157,7 +157,7 @@ public extension JobQueue {
return
}
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
guard let nextJob: JobRecordType = self.finder.getNextReady(label: self.jobRecordLabel, transaction: transaction) as? JobRecordType else {
Logger.verbose("nothing left to enqueue")
return
@ -197,7 +197,7 @@ public extension JobQueue {
}
public func restartOldJobs() {
self.dbConnection.readWrite { transaction in
try! Storage.writeSync { transaction in
let runningRecords = self.finder.allRecords(label: self.jobRecordLabel, status: .running, transaction: transaction)
Logger.info("marking old `running` JobRecords as ready: \(runningRecords.count)")
for record in runningRecords {

Loading…
Cancel
Save