Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: async workflows #306

Merged
merged 30 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2e66902
promise hook and tests
thantos Feb 10, 2023
f22dd6c
feat: async workflow executor
thantos Mar 3, 2023
057b074
fix...
thantos Mar 3, 2023
8484f38
tests pass
thantos Mar 3, 2023
4f35d15
feedback
thantos Mar 5, 2023
a00fd19
simplify test env, fix bugs, remove async transformer
thantos Mar 5, 2023
ce4a7d1
more test refactoring
thantos Mar 5, 2023
8da98d8
fix replay bug
thantos Mar 5, 2023
c4ea0ea
signal handler access to workflow hook
thantos Mar 5, 2023
95116f2
move commands to core runtime
thantos Mar 5, 2023
aec39b7
simplify await timer calls
thantos Mar 6, 2023
44bcb65
refactor executor
thantos Mar 6, 2023
a0f7b94
old spelling error
thantos Mar 6, 2023
1ac48bd
test continue
thantos Mar 6, 2023
94ef5f7
fix some tests
thantos Mar 6, 2023
724e7ac
fix tests
thantos Mar 6, 2023
31fd5fa
cleanup
thantos Mar 7, 2023
fe4538d
date hook with async local store
thantos Mar 7, 2023
58f34bc
docs
thantos Mar 7, 2023
3141700
support events after workflow success
thantos Mar 7, 2023
8755120
clean up
thantos Mar 7, 2023
169e295
fix date bug
thantos Mar 7, 2023
cf3069d
revert als
thantos Mar 8, 2023
7ef962f
Merge branch 'sussman/async_workflows' of https://github.com/function…
thantos Mar 8, 2023
9f81bf7
Merge branch 'main' into sussman/async_workflows
thantos Mar 8, 2023
1bce98b
workflow failures
thantos Mar 8, 2023
b262d57
reenable the chaos ext
thantos Mar 8, 2023
fb25b0f
speed and clean up
thantos Mar 8, 2023
944dd90
testing then, catch, finally
thantos Mar 9, 2023
bb6a982
feedback
thantos Mar 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions packages/@eventual/cli/src/commands/replay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
Result,
resultToString,
ServiceType,
serviceTypeScopeSync,
serviceTypeScope,
workflows,
} from "@eventual/core/internal";
import path from "path";
Expand Down Expand Up @@ -62,7 +62,7 @@ export const replay = (yargs: Argv) =>
}
spinner.start("Running program");

serviceTypeScopeSync(ServiceType.OrchestratorWorker, () => {
serviceTypeScope(ServiceType.OrchestratorWorker, async () => {
const processedEvents = processEvents(
events,
[],
Expand All @@ -74,7 +74,11 @@ export const replay = (yargs: Argv) =>
)
);

const res = progressWorkflow(execution, workflow, processedEvents);
const res = await progressWorkflow(
execution,
workflow,
processedEvents
);

assertExpectedResult(executionObj, res.result);

Expand Down
6 changes: 3 additions & 3 deletions packages/@eventual/compiler/src/eventual-bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { aliasPath } from "esbuild-plugin-alias-path";
import fs from "fs/promises";
import path from "path";
import { prepareOutDir } from "./build.js";
import { eventualESPlugin } from "./esbuild-plugin.js";
// import { eventualESPlugin } from "./esbuild-plugin.js";

export async function bundleSources(
outDir: string,
Expand Down Expand Up @@ -65,7 +65,7 @@ export async function build({
injectedServiceSpec,
name,
entry,
eventualTransform = false,
// eventualTransform = false,
thantos marked this conversation as resolved.
Show resolved Hide resolved
sourcemap,
serviceType,
external,
Expand Down Expand Up @@ -102,7 +102,7 @@ export async function build({
}),
]
: []),
...(eventualTransform ? [eventualESPlugin] : []),
// ...(eventualTransform ? [eventualESPlugin] : []),
],
conditions: ["module", "import", "require"],
// external: ["@aws-sdk"],
Expand Down
199 changes: 59 additions & 140 deletions packages/@eventual/compiler/test/__snapshots__/infer-plugin.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -445,77 +445,25 @@ module.exports = __toCommonJS(command_worker_exports);

var AsyncTokenSymbol = Symbol.for("eventual:AsyncToken");

function createAwaitAllSettled(activities2) {
return createEventual(EventualKind.AwaitAllSettled, {
activities: activities2
});
}

function createAwaitAll(activities2) {
return createEventual(EventualKind.AwaitAll, {
activities: activities2
});
}

function createAwaitAny(activities2) {
return createEventual(EventualKind.AwaitAny, {
activities: activities2
});
}

globalThis._eventual ??= {};
var commands = globalThis._eventual.commands ??= [];
var eventualCollector = () => {
const collector = globalThis._eventual.eventualCollector;
if (!collector) {
throw new Error("No Eventual Collector Provided");
}
return collector;
};
function registerEventual(eventual) {
return eventualCollector().pushEventual(eventual);
}

function or(...conditions) {
return (a) => conditions.some((cond) => cond(a));
}

var ResultSymbol = Symbol.for("eventual:Result");
var ResultKind;
(function(ResultKind2) {
ResultKind2[ResultKind2["Pending"] = 0] = "Pending";
ResultKind2[ResultKind2["Resolved"] = 1] = "Resolved";
ResultKind2[ResultKind2["Failed"] = 2] = "Failed";
})(ResultKind || (ResultKind = {}));
function isResult(a) {
return a && typeof a === "object" && ResultSymbol in a;
}
function isResolved(result) {
return isResult(result) && result[ResultSymbol] === ResultKind.Resolved;
}
function isFailed(result) {
return isResult(result) && result[ResultSymbol] === ResultKind.Failed;
}
var isResolvedOrFailed = or(isResolved, isFailed);

var SignalTargetType;
(function(SignalTargetType2) {
SignalTargetType2[SignalTargetType2["Execution"] = 0] = "Execution";
SignalTargetType2[SignalTargetType2["ChildExecution"] = 1] = "ChildExecution";
})(SignalTargetType || (SignalTargetType = {}));

function chain(func) {
return (...args) => {
const generator = func(...args);
return registerChain(generator);
};
}
function createChain(program) {
return createEventual(EventualKind.Chain, program);
}
function registerChain(program) {
return registerEventual(createChain(program));
}
var EventualPromiseSymbol = Symbol.for("Eventual:Promise");

var EventualCallKind;
(function(EventualCallKind2) {
EventualCallKind2[EventualCallKind2["ActivityCall"] = 1] = "ActivityCall";
EventualCallKind2[EventualCallKind2["AwaitAll"] = 0] = "AwaitAll";
EventualCallKind2[EventualCallKind2["AwaitAllSettled"] = 12] = "AwaitAllSettled";
EventualCallKind2[EventualCallKind2["AwaitAny"] = 10] = "AwaitAny";
EventualCallKind2[EventualCallKind2["AwaitDurationCall"] = 3] = "AwaitDurationCall";
EventualCallKind2[EventualCallKind2["AwaitTimeCall"] = 4] = "AwaitTimeCall";
EventualCallKind2[EventualCallKind2["ConditionCall"] = 9] = "ConditionCall";
EventualCallKind2[EventualCallKind2["ExpectSignalCall"] = 6] = "ExpectSignalCall";
EventualCallKind2[EventualCallKind2["PublishEventsCall"] = 13] = "PublishEventsCall";
EventualCallKind2[EventualCallKind2["Race"] = 11] = "Race";
EventualCallKind2[EventualCallKind2["RegisterSignalHandlerCall"] = 7] = "RegisterSignalHandlerCall";
EventualCallKind2[EventualCallKind2["SendSignalCall"] = 8] = "SendSignalCall";
EventualCallKind2[EventualCallKind2["WorkflowCall"] = 5] = "WorkflowCall";
})(EventualCallKind || (EventualCallKind = {}));
var EventualCallSymbol = Symbol.for("eventual:EventualCall");

var ServiceType;
(function(ServiceType2) {
Expand All @@ -525,72 +473,8 @@ var ServiceType;
ServiceType2["OrchestratorWorker"] = "OrchestratorWorker";
})(ServiceType || (ServiceType = {}));

var SERVICE_TYPE_FLAG = "EVENTUAL_SERVICE_TYPE";
function isOrchestratorWorker() {
return process.env[SERVICE_TYPE_FLAG] === ServiceType.OrchestratorWorker;
}

function createRace(activities2) {
return createEventual(EventualKind.Race, {
activities: activities2
});
}

var EventualSymbol = Symbol.for("eventual:Eventual");
var EventualKind;
(function(EventualKind2) {
EventualKind2[EventualKind2["ActivityCall"] = 1] = "ActivityCall";
EventualKind2[EventualKind2["AwaitAll"] = 0] = "AwaitAll";
EventualKind2[EventualKind2["AwaitAllSettled"] = 12] = "AwaitAllSettled";
EventualKind2[EventualKind2["AwaitAny"] = 10] = "AwaitAny";
EventualKind2[EventualKind2["AwaitDurationCall"] = 3] = "AwaitDurationCall";
EventualKind2[EventualKind2["AwaitTimeCall"] = 4] = "AwaitTimeCall";
EventualKind2[EventualKind2["Chain"] = 2] = "Chain";
EventualKind2[EventualKind2["ConditionCall"] = 9] = "ConditionCall";
EventualKind2[EventualKind2["ExpectSignalCall"] = 6] = "ExpectSignalCall";
EventualKind2[EventualKind2["PublishEventsCall"] = 13] = "PublishEventsCall";
EventualKind2[EventualKind2["Race"] = 11] = "Race";
EventualKind2[EventualKind2["RegisterSignalHandlerCall"] = 7] = "RegisterSignalHandlerCall";
EventualKind2[EventualKind2["SendSignalCall"] = 8] = "SendSignalCall";
EventualKind2[EventualKind2["WorkflowCall"] = 5] = "WorkflowCall";
})(EventualKind || (EventualKind = {}));
function createEventual(kind, e2) {
e2[EventualSymbol] = kind;
return e2;
}
var Eventual = {
/**
* Wait for all {@link activities} to succeed or until at least one throws.
*
* This is the equivalent behavior to Promise.all.
*/
all(activities2) {
if (!isOrchestratorWorker()) {
throw new Error("Eventual.all is only valid in a workflow");
}
return createAwaitAll(activities2);
},
any(activities2) {
if (!isOrchestratorWorker()) {
throw new Error("Eventual.any is only valid in a workflow");
}
return createAwaitAny(activities2);
},
race(activities2) {
if (!isOrchestratorWorker()) {
throw new Error("Eventual.race is only valid in a workflow");
}
return createRace(activities2);
},
allSettled(activities2) {
if (!isOrchestratorWorker()) {
throw new Error("Eventual.allSettled is only valid in a workflow");
}
return createAwaitAllSettled(activities2);
}
};
globalThis.$eventual = chain;
globalThis.$Eventual = Eventual;
globalThis._eventual ??= {};
var commands = globalThis._eventual.commands ??= [];

function isSourceLocation(a) {
return a && typeof a === "object" && typeof a.fileName === "string" && typeof a.exportName === "string";
Expand Down Expand Up @@ -776,6 +660,34 @@ _BaseCachingSecret_value = /* @__PURE__ */ new WeakMap();

var import_ulidx2 = __toESM(require_dist2(), 1);

function or(...conditions) {
return (a) => conditions.some((cond) => cond(a));
}

var ResultSymbol = Symbol.for("eventual:Result");
var ResultKind;
(function(ResultKind2) {
ResultKind2[ResultKind2["Pending"] = 0] = "Pending";
ResultKind2[ResultKind2["Resolved"] = 1] = "Resolved";
ResultKind2[ResultKind2["Failed"] = 2] = "Failed";
})(ResultKind || (ResultKind = {}));
function isResult(a) {
return a && typeof a === "object" && ResultSymbol in a;
}
function isResolved(result) {
return isResult(result) && result[ResultSymbol] === ResultKind.Resolved;
}
function isFailed(result) {
return isResult(result) && result[ResultSymbol] === ResultKind.Failed;
}
var isResolvedOrFailed = or(isResolved, isFailed);

var SignalTargetType;
(function(SignalTargetType2) {
SignalTargetType2[SignalTargetType2["Execution"] = 0] = "Execution";
SignalTargetType2[SignalTargetType2["ChildExecution"] = 1] = "ChildExecution";
})(SignalTargetType || (SignalTargetType = {}));

var WorkflowEventType;
(function(WorkflowEventType2) {
WorkflowEventType2["ActivitySucceeded"] = "ActivitySucceeded";
Expand All @@ -797,6 +709,13 @@ var WorkflowEventType;
WorkflowEventType2["WorkflowRunStarted"] = "WorkflowRunStarted";
WorkflowEventType2["WorkflowTimedOut"] = "WorkflowTimedOut";
})(WorkflowEventType || (WorkflowEventType = {}));
var isScheduledEvent = or(isActivityScheduled, isChildWorkflowScheduled, isEventsPublished, isSignalSent, isTimerScheduled);
var isSucceededEvent = or(isActivitySucceeded, isChildWorkflowSucceeded, isTimerCompleted);
var isFailedEvent = or(isActivityFailed, isActivityHeartbeatTimedOut, isChildWorkflowFailed, isWorkflowTimedOut);
var isResultEvent = or(isSucceededEvent, isFailedEvent, isSignalReceived, isWorkflowTimedOut, isWorkflowRunStarted);
function isWorkflowRunStarted(event) {
return event.type === WorkflowEventType.WorkflowRunStarted;
}
function isActivityScheduled(event) {
return event.type === WorkflowEventType.ActivityScheduled;
}
Expand Down Expand Up @@ -831,6 +750,9 @@ function isTimerCompleted(event) {
return event.type === WorkflowEventType.TimerCompleted;
}
var isWorkflowCompletedEvent = or(isWorkflowFailed, isWorkflowSucceeded);
function isSignalReceived(event) {
return event.type === WorkflowEventType.SignalReceived;
}
function isSignalSent(event) {
return event.type === WorkflowEventType.SignalSent;
}
Expand All @@ -840,9 +762,6 @@ function isEventsPublished(event) {
function isWorkflowTimedOut(event) {
return event.type === WorkflowEventType.WorkflowTimedOut;
}
var isScheduledEvent = or(isActivityScheduled, isChildWorkflowScheduled, isEventsPublished, isSignalSent, isTimerScheduled);
var isSucceededEvent = or(isActivitySucceeded, isChildWorkflowSucceeded, isTimerCompleted);
var isFailedEvent = or(isActivityFailed, isActivityHeartbeatTimedOut, isChildWorkflowFailed, isWorkflowTimedOut);

var myHandler = api.get("/", async () => {
return new HttpResponse();
Expand Down
Loading