Skip to main content

DBOS Client

DBOSClient provides a programmatic way to interact with your DBOS application from external code. DBOSClient includes methods similar to DBOS that make sense to be used outside of a DBOS workflow or step, such as enqueueWorkflow or getEvent.

note

DBOSClient is included in the @dbos-inc/dbos-sdk package, the same package that used by DBOS applications. Where DBOS applications use the static DBOS class, external applications use the DBOSClient class instead.

class DBOSClient

interface EnqueueOptions {
workflowName: string;
workflowClassName: string;
queueName: string;
workflowID?: string;
appVersion?: string;
}

class DBOSClient {
static create(databaseUrl: string, systemDatabase?: string): Promise<DBOSClient>;
destroy(): Promise<void>;
async enqueue<T extends (...args: any[]) => Promise<any>>(
options: EnqueueOptions,
...args: Parameters<T>
): Promise<WorkflowHandle<Awaited<ReturnType<T>>>>;
retrieveWorkflow<T = unknown>(workflowID: string): WorkflowHandle<Awaited<T>>;
send<T>(destinationID: string, message: T, topic?: string, idempotencyKey?: string): Promise<void>;
getEvent<T>(workflowID: string, key: string, timeoutSeconds?: number): Promise<T | null>;
}

create

You construct a DBOSClient with the static create function.

The databaseUrl parameter is a standard PostgreSQL connection URI for the DBOS application database. Please see Configuring DBOS for more info.

DBOS Client needs to connect to the system database of your DBOS application. The system database is stored on the same database server as the application database and typically has the same name as your application database, but suffixed with _dbos_sys. If you are using a non-standard system database name in your DBOS application, you must also provide the name to DBOSClient.create.

Example:

import { DBOSClient } from "@dbos-inc/dbos-sdk";

const client = await DBOSClient.create(process.env.DBOS_DATABASE_URL);

destroy

Asynchronously destroys a DBOSClient instance.

enqueue

Enqueues a workflow, similar to passing a queue name to startWorkflow or using DBOS.withWorkflowQueue. Like startWorkflow, the enqueue method returns a WorkflowHandle that you can use to retrieve the workflow results asynchronously from an external application.

When enqueuing a workflow from within a DBOS application, the workflow and queue metadata can be retrieved automatically. However, since DBOSClient runs outside the DBOS application, the metadata must be specified explicitly.

Required metadata includes:

  • workflowName: The name of the workflow method being enqueued.
  • workflowClassName: The name of the class the workflow method is a member of.
  • queueName: The name of the WorkflowQueue to enqueue the workflow on.

Additional but optional metadata includes:

  • workflowID: The unique ID for the enqueued workflow. If left undefined, DBOS Client will generate a UUID. Please see Workflow IDs and Idempotency for more information.
  • appVersion: The version of your application that should process this workflow. If left undefined, it will be updated to the current version when the workflow is first dequeued. Please see Managing Application Versions for more information.

In addition to the EnqueueOptions described above, you must also provide the workflow arguments to enqueue. These are passed to enqueue after the initial EnqueueOptions parameter.

Since DBOS Client works independently of your DBOS application code, enqueue accepts whatever arguments you provide it without verifying if they match the workflow's expected argument types. However, you can get type safety by providing a function declaration type parameter to enqueue. This enables TypeScript to verify that the provided arguments match the provided declaration and to infer the returned WorkflowHandle result type.

Untyped Example:

// Because we did not provide a function type declaration to enqueue,
// there is no way to verify the workflow arguments are of the correct type.
const handle = await client.enqueue(
{
workflowName: 'indexDocument',
workflowClassName: 'DocumentDetective',
queueName: 'indexingQueue',
},
"https://arxiv.org/pdf/2208.13068");

// Explicitly specify the result type since we did not provide a
// function type declaration to enqueue.
const result: number = await handle.getResult();

Typed Example:

// TypeScript type declaration for our sample app workflow
declare class DocumentDetective {
static indexDocument(url: string): Promise<number>
}

// Because we provided the function type declaration to enqueue, TypeScript
// can validate the workflow parameters and infer the workflow return type.
const handle = await client.enqueue<typeof DocumentDetective.indexDocument>(
{
workflowName: 'indexDocument',
workflowClassName: 'DocumentDetective',
queueName: 'indexingQueue',
},
"https://arxiv.org/pdf/2208.13068");

// TypeScript can also infer the result type because
// we provided the function type declaration to enqueue
const result = await handle.getResult();
tip

TypeScript automatically generates type declarations during compilation of your DBOS application. You can copy or import the function type declaration from your application's generated declaration file (aka.d.ts file).

retrieveWorkflow

Retrieves a workflow by ID, similar to DBOS.retrieveWorkflow. Returns a WorkflowHandle that can be used to retrieve information about the workflow, including its current state and its eventual result.

Similar to enqueue, retrieveWorkflow can be made type safe by use of a class declaration and the ReturnType Utility Class.

Example:

const handle = client.retrieveWorkflow<ReturnType<IndexDocument>>(documentWFID);
const pageCount = await handle.getResult();

send

Sends a message to a specified workflow. Identical to DBOS.send.

warning

Since DBOS Client is running outside of a DBOS application, it is highly recommended that you use the idempotencyKey parameter in order to get exactly-once behavior.

getEvent

Retrieves an event published by workflowID for a given key using the events API. Identical to DBOS.getEvent