Eventual Client
The EventualClient
is an interface that provides a set of methods for interacting with and managing workflow executions, sending signals, emitting events, and interacting with async tasks in an Eventual Service. These methods allow external systems to communicate with and control the Eventual Service.
APIs
getWorkflows
Use getWorkflows
to list all of the available workflows defined within the service.
const response = await client.getWorkflows();
The response
contains a list of all the workflow names:
{
"workflows": [
{
"name": "workflow-a"
},
{
"name": "workflow-b"
}
]
}
startExecution
The startExecution
method allows you to directly start a workflow execution in the Eventual Service. It requires the workflow
to be executed, the input
data, and an optional executionName
. When called, startExecution
returns an ExecutionHandle
object that includes the executionId
of the newly started workflow and various methods that can be used to interact with it.
const execution = await client.startExecution({
workflow: "myWorkflow",
input: inputData,
});
To specify a workflow
, you can pass its unique name as a string
or a reference to a workflow
instance. For example:
const myWorkflow = workflow("myWorkflow", async() => { .. });
const execution = await client.startExecution({
// use a reference to the workflow
workflow: myWorkflow,
...
});
const execution = await client.startExecution({
// pass the workflow's ID as a string
workflow: "myWorkflow",
...
});
The executionName
is an optional field you can provide to identify a particular execution of a workflow. By assigning a unique name to your execution, you can ensure that only one instance of that workflow is running at a time. If you try to start a workflow with the same name twice, the service will ignore subsequent requests.
Here's an example of how to guarantee exactly one instance of a monthly reporting workflow is running:
await client.startExecution(
workflow: "monthlyReportWorkflow",
input,
name: "2023-01-01", // ensure only one workflow execution for this date exists
)
getExecution
Use getExecution
to get the data for an Execution
given an executionId
. It requires the executionId
as its first argument and returns a JSON object containing information such as its execution status
, startTime
as an ISO8601 string, workflowName
and a reference to its parent
execution if it is a child workflow.
Here's an example of how to use getExecution to retrieve the data for an execution with the executionId of "my-execution-id"
:
const execution = await client.getExecution("my-execution-id");
The returned object will have the following structure:
{
"id": "my-execution-id",
"status": "IN_PROGRESS",
"workflowName": "my-workflow",
"startTime": "2023-01-01T00:00Z",
"parent": {
"id": "<parent-execution-id>",
"seq": 123
}
}
ExecutionStatus
A workflow execution can be in one of three statuses:
IN_PROGRESS
- the execution is still runningSUCCEEDED
- the execution has completed successfullyFAILED
- the execution has completed unsuccessfully
getExecutions
To retrieve a list of workflow executions, you can call the getExecutions
method and pass in an options object. This object allows you to specify criteria to filter the results by.
const executions = await client.getExecutions({});
The method returns a JSON object containing a list of executions and an optional nextToken
. The executions array includes information such as the id
, status
, workflowName
, and startTime
of each execution, as well as a reference to its parent
execution (if it is a child workflow). The nextToken
can be used in subsequent requests to page through the results if there are more executions to retrieve.
{
"nextToken": "<optional-next-token",
"executions": [
{
"id": "my-execution-id",
"status": "IN_PROGRESS",
"workflowName": "my-workflow",
"startTime": "2023-01-01T00:00Z",
"parent": {
"id": "<parent-execution-id>",
"seq": 123
}
}
]
}
If nextToken
is present in the result, you must specify it in subsequent requests to page through results:
await client.getExecutions({
nextToken: response.nextToken,
});
To filter by a workflow execution's status, you can pass a list of the statuses
you want to include in the results. For example, this call will return all executions with a status of IN_PROGRESS
:
await client.getExecutions({
statuses: [ExecutionStatus.IN_PROGRESS],
});
You can also filter by the name of the workflow the execution belongs to by passing a string value to the workflowName
property.
await client.getExecutions({
workflowName: "myWorkflow",
});
By default, the getExecutions
method returns the first 100
results in ascending order of the execution's startTime
. You can limit the number of results returned by specifying maxResults
and change the order of the results by specifying sortDirection
as "Asc" for ascending or "Desc" for descending.
await client.getExecutions({
maxResults: 10,
sortOrder: "Desc",
});
getExecutionHistory
The getExecutionHistory
method allows you to retrieve the event history log for a specific workflow execution. It requires the executionId
of the execution you want to download the history for as its input. For example:
const history = await client.getExecutionHistory({
executionId: "my-execution-id",
});
The method returns a JSON object containing the events
and nextToken
that can be used in subsequent requests to page through the results.
{
"events": [
{
"type": "WorkflowRunStarted",
"id": "<event-id>",
"timestamp": "2023-01-01T00:00Z"
}
],
"nextToken": "<optional next token for pagination"
}
See the Workflow Events section for a list of possible event types that can occur in a workflow.
To retrieve subsequent pages of a workflow execution's history log, you can specify the nextToken
returned in the previous response in a subsequent call to getExecutionHistory
. This allows you to paginate through the results and retrieve the full history log of a workflow execution. For example:
const history = await client.getExecutionHistory({
executionId: "my-execution-id",
nextToken: response.nextToken,
});
By default, a single call returns 100
results, but to retrieve a specific number of results from the event history log of a workflow execution, you can use the maxResults
option. To specify the order in which events should be returned, use the sortDirection
option and set it to either "Asc"
or "Desc"
. The default value is "Asc"
, which returns events in ascending order. For example:
const history = await client.getExecutionHistory({
executionId: "my-execution-id",
maxResults: 50,
sortDirection: "Desc",
});
WorkflowEvent
TaskSucceeded
TaskFailed
TaskHeartbeatTimedOut
TaskScheduled
TaskTimedOut
ChildWorkflowSucceeded
ChildWorkflowFailed
ChildWorkflowScheduled
ConditionStarted
ConditionTimedOut
EventsEmitted
ExpectSignalStarted
ExpectSignalTimedOut
EntityRequest
EntityRequestFailed
EntityRequestSucceeded
SignalReceived
SignalSent
SleepCompleted
SleepScheduled
TransactionRequest
TransactionRequestFailed
TransactionRequestSucceeded
WorkflowSucceeded
WorkflowFailed
WorkflowStarted
WorkflowRunCompleted
WorkflowRunStarted
WorkflowTimedOut
sendSignal
Use sendSignal
to send a Signal to a running workflow execution. It requires an execution
to send the signal to, the signal
to send and an optional payload
.
Here is an example of how to use sendSignal
:
await client.sendSignal({
execution: "my-execution-id",
signal: "my-signal-name",
payload: "my-payload",
});
You can reference a signal
by its unique name as a string
like above, or pass a reference to the signal instance. For example:
const mySignal = signal("my-signal-name");
await client.sendSignal({
execution: "my-execution-id",
signal: mySignal,
});
emitEvents
Use emitEvents
to emit one or more Events
to a service. It accepts a list of events
to emit.
await client.emit({
events: [
{
// the unique name of the event type
name: "my-event-name",
// the event payload
event: {
key: "value",
// ..
},
},
],
});
sendTaskSuccess
The sendTaskSuccess
method is used to mark an async task as successfully completed. This is done by providing the taskToken
and the result
of the task. This method is typically called after the task has been performed and the result has been computed.
await client.sendTaskSuccess({
taskToken: "my-token",
result: "result payload",
});
sendTaskFailure
The sendTaskFailure
method is used to mark an asynchronous task as failed. This is done by providing the taskToken
and the error
that caused the failure. This method is typically called when an error occurs during the performance of the task.
await client.sendTaskFailure({
taskToken: token,
error: new Error("failure"),
});
sendTaskHeartbeat
The sendTaskHeartbeat
method is used to send a Heartbeat indicating that the task is still being actively worked on. It requires the taskToken: string;
of the task request that is being processed.
await client.sendTaskHeartbeat({
taskToken: "<task-token>",
});
See the Heartbeat Documentation for more information on asynchronous task heartbeats.
Implementations
There are several implementations of the EventualClient
interface that are useful in different runtime contexts:
HttpServiceClient
The HttpServiceClient
is an HTTP implementation available in @eventual/client
that allows you to make unauthenticated and unsigned requests to the API deployed with an Eventual Service using fetch. It is the base client for interacting with an Eventual Service over HTTP from outside of a managed Eventual environment.
To authorize and/or sign requests, you can use the beforeRequest
hook or an existing platform-specific client, such as the AwsHttpServiceClient
in @eventual/aws-client
.
Here is an example of how to use the HttpServiceClient
:
const client = new HttpServiceClient({
serviceUrl: "<http-service-url>",
});
const workflows = await client.getWorkflows();
AwsHttpServiceClient
The AwsHttpServiceClient
is an AWS-specific HTTP implementation that allows you to make authorized and signed requests to API Gateway using the credentials provided on construction. This client is available in @eventual/aws-client
.
npm install --save @eventual/aws-client
Use this client if you're running within an AWS environment and wish to authenticate with your Eventual Service using AWS IAM.
Here's an example of how to create and used an AwsHttpServiceClient
:
const client = new AwsHttpServiceClient({
serviceUrl: "<http-service-url>",
});
const workflows = await client.getWorkflows();
The client uses your default credential chain by default, which should "just work" when running from within an environment such as an AWS Lambda Function. To override this behavior, specify the credentials
when creating the client. You can pass any valid AwsCredentialIdentity
or AwsCredentialIdentityProvider
.
const client = new AwsHttpServiceClient({
serviceUrl: "<http-service-url>",
credentials: myCredentials,
});
RuntimeServiceClient
The RuntimeServiceClient
available in @eventual/core
is an implementation that uses the Eventual runtime clients. It is intended to be used when there is direct access to the internals of an Eventual Service - this is true only when inside API, event or task handler functions. This client has the advantaged of being more performant by avoiding the hop over HTTP but requires privileged access to service internals.
To get an instance of this client, call the global getServiceClient
from @eventual/core
when within an API, event or task handler function.
import { getServiceClient } from "@eventual/core";
const client = getServiceClient();
TestEnvironment
The TestEnvironment
is a locally simulated workflow environment designed for unit testing, available in the @eventual/testing
package. It implements a local and mockable version of the EventualClient interface, allowing you to provide mock implementations of tasks and workflows, manually progress time, and more.
See the Unit Testing docs.