Skip to content

App crashes when canceling a task that contains an asynchronous GRDB write operation #1838

@sepw

Description

@sepw

I start a task that writes to a database queue asynchronously using:

let task = Task {
  try await queue.write {
    ...
    try Task.checkCancellation()
    ...
  }
}

I'm attempting to cancel the task using

task.cancel()

and the app crashes with the following error:

GRDB/SerializedDatabase.swift:261: Fatal error: A transaction has been left opened at the end of a database access

I only get this fatal error from GRDB when the task is cancelled. The write transaction is rolled back correctly when I throw an application-defined error from the closure passed to the database writer's write(_:) function:

let task = Task {
  try await queue.write {
    ...
    throw AppError.oops
    ...
  }
}

According to the GRDB documentation for DatabaseWriter's func write(_:) async throws, cancellation of a task performing a write is legal and supported:

extension DatabaseWriter {

    /// ...
    /// - throws: Any ``DatabaseError`` that happens while establishing the
    ///   database access, or the error thrown by `updates`, or
    ///   `CancellationError` if the task is cancelled.
    public func write<T: Sendable>(
        _ updates: @Sendable (Database) throws -> T
    ) async throws -> T
}

Is there something I should be doing to handle cancellation errors in asynchronous database read or write closures?

GRDB version: 7.8.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions