π Β Eventual is in pre-release - come chat to us on Discord!
Website β’ API Docs β’ Quick Start
Eventual makes building and operating resilient event-driven applications easy at any scale.
- πͺΒ Powerful orchestration and choreography - build durable, long-running Workflows, scale APIs, publish and subscribe to Events, and connect to SaaS via Integrations.
- πΒ Event-driven - build asynchronous systems that are more resilient, scalable and evolvable.
- πΒ Serverless - fully serverless, load-based pricing that scales to $0 and minimal operational complexity.
- π§©Β Composable and Evolvable - loosely coupled architectures make it easy to add new services and evolve your system over time.
- π§βπ»Β Code-first - end-to-end type safety that spans across service boundaries, from APIs to Events to long-running Workflows.
- π©Β Your cloud, your security boundaries - runs on your cloud infrastructure, with transparent billing and total control over data and security.
- π Β Distributed as IaC - integrates with your favorite Infrastructure-as-Code (IaC) frameworks such as the AWS CDK and SST.
Start a new project with Eventual or drop-in to an existing AWS CDK or SST application by visiting the Quick Start.
# create a new project
npm create eventual
# enter the new project's directory
cd <project-name>
# deploy to AWS
npx cdk deploy
Eventual makes building and operating resilient event-driven applications easy at any scale. Its code-first workflow engine and event-driven primitives simplify and standardize how teams solve complex business orchestration problems and evolve system architectures over time. Leverages Serverless to scale from 0 to any sized workload and your favorite Infrastructure-as-Code framework to drop directly in to your stack without getting in your way.
We highly recommend checking out Werner Vogel's 2022 AWS RE:Invent Keynote.
With our plug-and-play foundation blocks, you can use as much or as little as needed to build your distributed system. These building blocks include:
Easily create scalable, event-driven APIs with code-first routes.
import { api } from "@eventual/core";
api.post("/echo", async (request) => {
return new Response(await request.text());
});
import { event } from "@eventual/core";
interface MyEvent {
key: string;
}
export const myEvent = event<MyEvent>("MyEvent");
myEvent.onEvent((e) => {
console.log(e.key);
});
Eventual allows you to use the full power of TypeScript to build long-running, durable workflows with unlimited complexity - including operators, for-loops, try-catch, if-else, while, do-while, etc.
export const myWorkflow = workflow("myWorkflow", async (items: string[]) => {
try {
await Promise.all(
items.map(async (item) => {
if (isConditionTrue(item)) {
await downStreamService(`hello ${item}`);
}
})
);
} catch (err) {
console.error(err);
}
});
Easily unit test your service's business logic, including APIs, workflows, and event handlers, using your preferred testing practices and frameworks. Run tests locally or within your CI/CD pipeline to ensure your service is reliable and maintainable.
import { myWorkflow } from "../src/my-workflow";
const env = new TestEnvironment({
entry: path.join(__dirname, "..", "src", "my-workflow.ts")
})
test("workflow should be OK", async () => {
const execution = await env.startExecution(myWorkflow, ({
hello: "world",
});
// advance time
await env.tick(1);
expect(await execution.getStatus()).toMatchObject({
status: ExecutionStatus.SUCCESS
});
});
Replay problematic workflows in production locally and use your IDE's debugger to discover and fix problems.
eventual replay execution <execution-id> --entry ./src/index.ts
import { Slack, SlackCredentials } from "@eventual/integrations-slack";
import { AWSSecret } from "@eventual/aws-client";
const slack = new Slack("my-slack-connection", {
credentials: new JsonSecret<SlackCredentials>(
new AWSSecret({
secretId: process.env.SLACK_SECRET_ID!,
})
),
});
// register a webhook for a slack command
slack.command("/ack", async (request) => {
await sendSignal(request.text, "ack");
request.ack();
});
export const task = workflow("task", async (request) => {
await expectSignal("ack");
// publish a message to slack from a workflow
await slack.client.chat.postMessage({
channel: request.channel,
text: `Complete: ${request.task}`,
});
});