Skip to content

feat: allow providing abortSignal to go() method #545

@anatolzak

Description

@anatolzak

Summary

Add support for passing an AbortSignal to the go() query options, enabling cancellation of in-flight DynamoDB operations.

Motivation

Long-running operations like paginated queries, bulk operations, and scans can be resource-intensive and may need to be cancelled in scenarios such as:

  • Request timeouts in serverless functions (Lambda, etc.)
  • User-initiated cancellation in UI applications
  • Circuit breaker patterns in microservices

Currently, once a query is initiated, there's no way to cancel it mid-execution. This feature provides a standard, idiomatic way to handle cancellation using the web-standard AbortController/AbortSignal API.

Proposed API

const controller = new AbortController();

// Pass abortSignal to go() options
const result = await entity.query
  .record({ prop1: "value" })
  .go({ abortSignal: controller.signal });

// Cancel the operation at any time
controller.abort();

Supported Operations

The abortSignal option should work with all ElectroDB operations:

Expected Behavior

  1. Pre-aborted signals: If the signal is already aborted when go() is called, the operation should immediately throw an error without making any DynamoDB requests.

  2. Mid-execution abort: For operations that involve multiple requests (paginated queries with pages: "all", bulk operations, hydration), the abort signal should be checked:

    • Before each page fetch in paginated queries
    • Before each batch in bulk get/write operations
    • Between the initial query and hydration batch get
  3. Error handling: When aborted, operations should throw an ElectroError with:

    • Code: 4002
    • Error name: OperationAborted
    • Message: "The operation was aborted"

Usage Examples

Timeout Pattern

// Abort after 5 seconds
const result = await entity.query
  .record({ prop1: "value" })
  .go({ 
    abortSignal: AbortSignal.timeout(5000),
    pages: "all"
  });

Manual Cancellation

const controller = new AbortController();

// Start long-running scan
const scanPromise = entity.scan.go({ 
  abortSignal: controller.signal,
  pages: "all"
});

// Cancel after some condition
someEventEmitter.on('cancel', () => controller.abort());

try {
  const result = await scanPromise;
} catch (err) {
  if (err.code === 4002) {
    console.log('Operation was cancelled');
  }
}

AWS SDK Compatibility

This feature should work with both AWS SDK versions:

  • v2: Uses the request.abort() method on the AWS.Request object
  • v3: Passes the abortSignal directly to the client.send() options

TypeScript Support

The abortSignal option should be typed in QueryOptions and related interfaces:

interface QueryOptions {
  // ... existing options
  abortSignal?: AbortSignal;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions