@dbos-inc/dbos-sdk 0.7.18-preview
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/dbos-config.schema.json +121 -0
- package/dbos-test-config.yaml +16 -0
- package/dist/schemas/system_db_schema.d.ts +34 -0
- package/dist/schemas/system_db_schema.d.ts.map +1 -0
- package/dist/schemas/system_db_schema.js +75 -0
- package/dist/schemas/system_db_schema.js.map +1 -0
- package/dist/schemas/user_db_schema.d.ts +11 -0
- package/dist/schemas/user_db_schema.d.ts.map +1 -0
- package/dist/schemas/user_db_schema.js +16 -0
- package/dist/schemas/user_db_schema.js.map +1 -0
- package/dist/src/cloud-cli/applications/configure.d.ts +2 -0
- package/dist/src/cloud-cli/applications/configure.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/configure.js +57 -0
- package/dist/src/cloud-cli/applications/configure.js.map +1 -0
- package/dist/src/cloud-cli/applications/delete-app.d.ts +2 -0
- package/dist/src/cloud-cli/applications/delete-app.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/delete-app.js +36 -0
- package/dist/src/cloud-cli/applications/delete-app.js.map +1 -0
- package/dist/src/cloud-cli/applications/deploy-app-code.d.ts +2 -0
- package/dist/src/cloud-cli/applications/deploy-app-code.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/deploy-app-code.js +64 -0
- package/dist/src/cloud-cli/applications/deploy-app-code.js.map +1 -0
- package/dist/src/cloud-cli/applications/get-app-logs.d.ts +2 -0
- package/dist/src/cloud-cli/applications/get-app-logs.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/get-app-logs.js +37 -0
- package/dist/src/cloud-cli/applications/get-app-logs.js.map +1 -0
- package/dist/src/cloud-cli/applications/index.d.ts +8 -0
- package/dist/src/cloud-cli/applications/index.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/index.js +18 -0
- package/dist/src/cloud-cli/applications/index.js.map +1 -0
- package/dist/src/cloud-cli/applications/list-apps.d.ts +2 -0
- package/dist/src/cloud-cli/applications/list-apps.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/list-apps.js +45 -0
- package/dist/src/cloud-cli/applications/list-apps.js.map +1 -0
- package/dist/src/cloud-cli/applications/register-app.d.ts +2 -0
- package/dist/src/cloud-cli/applications/register-app.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/register-app.js +41 -0
- package/dist/src/cloud-cli/applications/register-app.js.map +1 -0
- package/dist/src/cloud-cli/applications/types.d.ts +7 -0
- package/dist/src/cloud-cli/applications/types.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/types.js +3 -0
- package/dist/src/cloud-cli/applications/types.js.map +1 -0
- package/dist/src/cloud-cli/applications/update-app.d.ts +2 -0
- package/dist/src/cloud-cli/applications/update-app.d.ts.map +1 -0
- package/dist/src/cloud-cli/applications/update-app.js +42 -0
- package/dist/src/cloud-cli/applications/update-app.js.map +1 -0
- package/dist/src/cloud-cli/cli.d.ts +3 -0
- package/dist/src/cloud-cli/cli.d.ts.map +1 -0
- package/dist/src/cloud-cli/cli.js +148 -0
- package/dist/src/cloud-cli/cli.js.map +1 -0
- package/dist/src/cloud-cli/login.d.ts +7 -0
- package/dist/src/cloud-cli/login.d.ts.map +1 -0
- package/dist/src/cloud-cli/login.js +40 -0
- package/dist/src/cloud-cli/login.js.map +1 -0
- package/dist/src/cloud-cli/register.d.ts +2 -0
- package/dist/src/cloud-cli/register.d.ts.map +1 -0
- package/dist/src/cloud-cli/register.js +35 -0
- package/dist/src/cloud-cli/register.js.map +1 -0
- package/dist/src/cloud-cli/userdb.d.ts +4 -0
- package/dist/src/cloud-cli/userdb.d.ts.map +1 -0
- package/dist/src/cloud-cli/userdb.js +149 -0
- package/dist/src/cloud-cli/userdb.js.map +1 -0
- package/dist/src/cloud-cli/utils.d.ts +3 -0
- package/dist/src/cloud-cli/utils.d.ts.map +1 -0
- package/dist/src/cloud-cli/utils.js +17 -0
- package/dist/src/cloud-cli/utils.js.map +1 -0
- package/dist/src/communicator.d.ts +24 -0
- package/dist/src/communicator.d.ts.map +1 -0
- package/dist/src/communicator.js +26 -0
- package/dist/src/communicator.js.map +1 -0
- package/dist/src/context.d.ts +60 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +94 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/data_validation.d.ts +3 -0
- package/dist/src/data_validation.d.ts.map +1 -0
- package/dist/src/data_validation.js +168 -0
- package/dist/src/data_validation.js.map +1 -0
- package/dist/src/dbos-executor.d.ts +79 -0
- package/dist/src/dbos-executor.d.ts.map +1 -0
- package/dist/src/dbos-executor.js +408 -0
- package/dist/src/dbos-executor.js.map +1 -0
- package/dist/src/dbos-runtime/TypeParser.d.ts +33 -0
- package/dist/src/dbos-runtime/TypeParser.d.ts.map +1 -0
- package/dist/src/dbos-runtime/TypeParser.js +104 -0
- package/dist/src/dbos-runtime/TypeParser.js.map +1 -0
- package/dist/src/dbos-runtime/applicationVersion.d.ts +3 -0
- package/dist/src/dbos-runtime/applicationVersion.d.ts.map +1 -0
- package/dist/src/dbos-runtime/applicationVersion.js +13 -0
- package/dist/src/dbos-runtime/applicationVersion.js.map +1 -0
- package/dist/src/dbos-runtime/cli.d.ts +8 -0
- package/dist/src/dbos-runtime/cli.d.ts.map +1 -0
- package/dist/src/dbos-runtime/cli.js +52 -0
- package/dist/src/dbos-runtime/cli.js.map +1 -0
- package/dist/src/dbos-runtime/config.d.ts +28 -0
- package/dist/src/dbos-runtime/config.d.ts.map +1 -0
- package/dist/src/dbos-runtime/config.js +111 -0
- package/dist/src/dbos-runtime/config.js.map +1 -0
- package/dist/src/dbos-runtime/init.d.ts +7 -0
- package/dist/src/dbos-runtime/init.d.ts.map +1 -0
- package/dist/src/dbos-runtime/init.js +51 -0
- package/dist/src/dbos-runtime/init.js.map +1 -0
- package/dist/src/dbos-runtime/openApi.d.ts +35 -0
- package/dist/src/dbos-runtime/openApi.d.ts.map +1 -0
- package/dist/src/dbos-runtime/openApi.js +595 -0
- package/dist/src/dbos-runtime/openApi.js.map +1 -0
- package/dist/src/dbos-runtime/runtime.d.ts +28 -0
- package/dist/src/dbos-runtime/runtime.d.ts.map +1 -0
- package/dist/src/dbos-runtime/runtime.js +96 -0
- package/dist/src/dbos-runtime/runtime.js.map +1 -0
- package/dist/src/dbos-runtime/tsDiagUtil.d.ts +16 -0
- package/dist/src/dbos-runtime/tsDiagUtil.d.ts.map +1 -0
- package/dist/src/dbos-runtime/tsDiagUtil.js +72 -0
- package/dist/src/dbos-runtime/tsDiagUtil.js.map +1 -0
- package/dist/src/decorators.d.ts +118 -0
- package/dist/src/decorators.d.ts.map +1 -0
- package/dist/src/decorators.js +467 -0
- package/dist/src/decorators.js.map +1 -0
- package/dist/src/error.d.ts +44 -0
- package/dist/src/error.d.ts.map +1 -0
- package/dist/src/error.js +164 -0
- package/dist/src/error.js.map +1 -0
- package/dist/src/httpServer/handler.d.ts +62 -0
- package/dist/src/httpServer/handler.d.ts.map +1 -0
- package/dist/src/httpServer/handler.js +168 -0
- package/dist/src/httpServer/handler.js.map +1 -0
- package/dist/src/httpServer/middleware.d.ts +56 -0
- package/dist/src/httpServer/middleware.d.ts.map +1 -0
- package/dist/src/httpServer/middleware.js +57 -0
- package/dist/src/httpServer/middleware.js.map +1 -0
- package/dist/src/httpServer/server.d.ts +40 -0
- package/dist/src/httpServer/server.d.ts.map +1 -0
- package/dist/src/httpServer/server.js +231 -0
- package/dist/src/httpServer/server.js.map +1 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +75 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/provenance/provenance_daemon.d.ts +34 -0
- package/dist/src/provenance/provenance_daemon.d.ts.map +1 -0
- package/dist/src/provenance/provenance_daemon.js +86 -0
- package/dist/src/provenance/provenance_daemon.js.map +1 -0
- package/dist/src/system_database.d.ts +69 -0
- package/dist/src/system_database.d.ts.map +1 -0
- package/dist/src/system_database.js +384 -0
- package/dist/src/system_database.js.map +1 -0
- package/dist/src/telemetry/collector.d.ts +17 -0
- package/dist/src/telemetry/collector.d.ts.map +1 -0
- package/dist/src/telemetry/collector.js +77 -0
- package/dist/src/telemetry/collector.js.map +1 -0
- package/dist/src/telemetry/exporters.d.ts +29 -0
- package/dist/src/telemetry/exporters.d.ts.map +1 -0
- package/dist/src/telemetry/exporters.js +186 -0
- package/dist/src/telemetry/exporters.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +7 -0
- package/dist/src/telemetry/index.d.ts.map +1 -0
- package/dist/src/telemetry/index.js +3 -0
- package/dist/src/telemetry/index.js.map +1 -0
- package/dist/src/telemetry/logs.d.ts +25 -0
- package/dist/src/telemetry/logs.d.ts.map +1 -0
- package/dist/src/telemetry/logs.js +91 -0
- package/dist/src/telemetry/logs.js.map +1 -0
- package/dist/src/telemetry/signals.d.ts +30 -0
- package/dist/src/telemetry/signals.d.ts.map +1 -0
- package/dist/src/telemetry/signals.js +11 -0
- package/dist/src/telemetry/signals.js.map +1 -0
- package/dist/src/telemetry/traces.d.ts +17 -0
- package/dist/src/telemetry/traces.d.ts.map +1 -0
- package/dist/src/telemetry/traces.js +76 -0
- package/dist/src/telemetry/traces.js.map +1 -0
- package/dist/src/testing/testing_runtime.d.ts +76 -0
- package/dist/src/testing/testing_runtime.d.ts.map +1 -0
- package/dist/src/testing/testing_runtime.js +147 -0
- package/dist/src/testing/testing_runtime.js.map +1 -0
- package/dist/src/transaction.d.ts +28 -0
- package/dist/src/transaction.d.ts.map +1 -0
- package/dist/src/transaction.js +27 -0
- package/dist/src/transaction.js.map +1 -0
- package/dist/src/user_database.d.ts +132 -0
- package/dist/src/user_database.d.ts.map +1 -0
- package/dist/src/user_database.js +324 -0
- package/dist/src/user_database.js.map +1 -0
- package/dist/src/utils.d.ts +6 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +35 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/src/workflow.d.ts +179 -0
- package/dist/src/workflow.d.ts.map +1 -0
- package/dist/src/workflow.js +446 -0
- package/dist/src/workflow.js.map +1 -0
- package/examples/hello/README.md +41 -0
- package/examples/hello/dbos-config.yaml +15 -0
- package/examples/hello/jest.config.js +8 -0
- package/examples/hello/knexfile.ts +23 -0
- package/examples/hello/migrations/create_dbos_hello_tables.ts +12 -0
- package/examples/hello/package.json +21 -0
- package/examples/hello/src/operations.test.ts +38 -0
- package/examples/hello/src/operations.ts +21 -0
- package/examples/hello/start_postgres_docker.sh +23 -0
- package/examples/hello/tsconfig.json +24 -0
- package/package.json +78 -0
@@ -0,0 +1,446 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.RetrievedHandle = exports.InvokedHandle = exports.WorkflowContextImpl = exports.StatusString = void 0;
|
4
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
5
|
+
const dbos_executor_1 = require("./dbos-executor");
|
6
|
+
const transaction_1 = require("./transaction");
|
7
|
+
const communicator_1 = require("./communicator");
|
8
|
+
const error_1 = require("./error");
|
9
|
+
const serialize_error_1 = require("serialize-error");
|
10
|
+
const utils_1 = require("./utils");
|
11
|
+
const api_1 = require("@opentelemetry/api");
|
12
|
+
const context_1 = require("./context");
|
13
|
+
const decorators_1 = require("./decorators");
|
14
|
+
exports.StatusString = {
|
15
|
+
PENDING: "PENDING",
|
16
|
+
SUCCESS: "SUCCESS",
|
17
|
+
ERROR: "ERROR",
|
18
|
+
};
|
19
|
+
class WorkflowContextImpl extends context_1.DBOSContextImpl {
|
20
|
+
workflowConfig;
|
21
|
+
functionID = 0;
|
22
|
+
#wfe;
|
23
|
+
resultBuffer = new Map();
|
24
|
+
isTempWorkflow;
|
25
|
+
constructor(wfe, parentCtx, workflowUUID, workflowConfig, workflowName) {
|
26
|
+
const span = wfe.tracer.startSpan(workflowName, {
|
27
|
+
workflowUUID: workflowUUID,
|
28
|
+
operationName: workflowName,
|
29
|
+
runAs: parentCtx?.authenticatedUser ?? "",
|
30
|
+
}, parentCtx?.span);
|
31
|
+
super(workflowName, span, wfe.logger, parentCtx);
|
32
|
+
this.workflowConfig = workflowConfig;
|
33
|
+
this.workflowUUID = workflowUUID;
|
34
|
+
this.#wfe = wfe;
|
35
|
+
this.isTempWorkflow = wfe.tempWorkflowName === workflowName;
|
36
|
+
if (wfe.config.application) {
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
38
|
+
this.applicationConfig = wfe.config.application;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
functionIDGetIncrement() {
|
42
|
+
return this.functionID++;
|
43
|
+
}
|
44
|
+
/**
|
45
|
+
* Check if an operation has already executed in a workflow.
|
46
|
+
* If it previously executed succesfully, return its output.
|
47
|
+
* If it previously executed and threw an error, throw that error.
|
48
|
+
* Otherwise, return DBOSNull.
|
49
|
+
* Also return the transaction snapshot information of this current transaction.
|
50
|
+
*/
|
51
|
+
async checkExecution(client, funcID) {
|
52
|
+
// Note: we read the current snapshot, not the recorded one!
|
53
|
+
const rows = await this.#wfe.userDatabase.queryWithClient(client, "(SELECT output, error, pg_current_snapshot()::text as txn_snapshot, true as recorded FROM dbos.transaction_outputs WHERE workflow_uuid=$1 AND function_id=$2 UNION ALL SELECT null as output, null as error, pg_current_snapshot()::text as txn_snapshot, false as recorded) ORDER BY recorded", this.workflowUUID, funcID);
|
54
|
+
if (rows.length === 0 || rows.length > 2) {
|
55
|
+
this.logger.error("Unexpected! This should never happen. Returned rows: " + rows.toString());
|
56
|
+
throw new error_1.DBOSError("This should never happen. Returned rows: " + rows.toString());
|
57
|
+
}
|
58
|
+
const res = {
|
59
|
+
output: dbos_executor_1.dbosNull,
|
60
|
+
txn_snapshot: ""
|
61
|
+
};
|
62
|
+
// recorded=false row will be first because we used ORDER BY.
|
63
|
+
res.txn_snapshot = rows[0].txn_snapshot;
|
64
|
+
if (rows.length == 2) {
|
65
|
+
if (JSON.parse(rows[1].error) !== null) {
|
66
|
+
throw (0, serialize_error_1.deserializeError)(JSON.parse(rows[1].error));
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
res.output = JSON.parse(rows[1].output);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
return res;
|
73
|
+
}
|
74
|
+
/**
|
75
|
+
* Write all entries in the workflow result buffer to the database.
|
76
|
+
* If it encounters a primary key error, this indicates a concurrent execution with the same UUID, so throw an DBOSError.
|
77
|
+
*/
|
78
|
+
async flushResultBuffer(client) {
|
79
|
+
const funcIDs = Array.from(this.resultBuffer.keys());
|
80
|
+
if (funcIDs.length === 0) {
|
81
|
+
return;
|
82
|
+
}
|
83
|
+
funcIDs.sort();
|
84
|
+
try {
|
85
|
+
let sqlStmt = "INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, output, error, txn_id, txn_snapshot) VALUES ";
|
86
|
+
let paramCnt = 1;
|
87
|
+
const values = [];
|
88
|
+
for (const funcID of funcIDs) {
|
89
|
+
// Capture output and also transaction snapshot information.
|
90
|
+
// Initially, no txn_id because no queries executed.
|
91
|
+
const recorded = this.resultBuffer.get(funcID);
|
92
|
+
const output = recorded.output;
|
93
|
+
const txnSnapshot = recorded.txn_snapshot;
|
94
|
+
if (paramCnt > 1) {
|
95
|
+
sqlStmt += ", ";
|
96
|
+
}
|
97
|
+
sqlStmt += `($${paramCnt++}, $${paramCnt++}, $${paramCnt++}, $${paramCnt++}, null, $${paramCnt++})`;
|
98
|
+
values.push(this.workflowUUID, funcID, JSON.stringify(output), JSON.stringify(null), txnSnapshot);
|
99
|
+
}
|
100
|
+
this.logger.debug(sqlStmt);
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
102
|
+
await this.#wfe.userDatabase.queryWithClient(client, sqlStmt, ...values);
|
103
|
+
}
|
104
|
+
catch (error) {
|
105
|
+
if (this.#wfe.userDatabase.isKeyConflictError(error)) {
|
106
|
+
// Serialization and primary key conflict (Postgres).
|
107
|
+
throw new error_1.DBOSWorkflowConflictUUIDError(this.workflowUUID);
|
108
|
+
}
|
109
|
+
else {
|
110
|
+
throw error;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
/**
|
115
|
+
* Buffer a placeholder value to guard an operation against concurrent executions with the same UUID.
|
116
|
+
*/
|
117
|
+
guardOperation(funcID, txnSnapshot) {
|
118
|
+
const guardOutput = {
|
119
|
+
output: null,
|
120
|
+
txn_snapshot: txnSnapshot,
|
121
|
+
};
|
122
|
+
this.resultBuffer.set(funcID, guardOutput);
|
123
|
+
}
|
124
|
+
/**
|
125
|
+
* Write a guarded operation's output to the database.
|
126
|
+
*/
|
127
|
+
async recordGuardedOutput(client, funcID, output) {
|
128
|
+
const serialOutput = JSON.stringify(output);
|
129
|
+
const rows = await this.#wfe.userDatabase.queryWithClient(client, "UPDATE dbos.transaction_outputs SET output=$1, txn_id=(select pg_current_xact_id_if_assigned()::text) WHERE workflow_uuid=$2 AND function_id=$3 RETURNING txn_id;", serialOutput, this.workflowUUID, funcID);
|
130
|
+
return rows[0].txn_id; // Must have a transaction ID because we inserted the guard before.
|
131
|
+
}
|
132
|
+
/**
|
133
|
+
* Record an error in a guarded operation to the database.
|
134
|
+
*/
|
135
|
+
async recordGuardedError(client, funcID, err) {
|
136
|
+
const serialErr = JSON.stringify((0, serialize_error_1.serializeError)(err));
|
137
|
+
await this.#wfe.userDatabase.queryWithClient(client, "UPDATE dbos.transaction_outputs SET error=$1 WHERE workflow_uuid=$2 AND function_id=$3;", serialErr, this.workflowUUID, funcID);
|
138
|
+
}
|
139
|
+
/**
|
140
|
+
* Invoke another workflow as its child workflow and return a workflow handle.
|
141
|
+
* The child workflow is guaranteed to be executed exactly once, even if the workflow is retried with the same UUID.
|
142
|
+
* We pass in itself as a parent context adn assign the child workflow with a derministic UUID "this.workflowUUID-functionID", which appends a function ID to its own UUID.
|
143
|
+
*/
|
144
|
+
async childWorkflow(wf, ...args) {
|
145
|
+
// Note: cannot use invoke for childWorkflow because of potential recursive types on the workflow itself.
|
146
|
+
const funcId = this.functionIDGetIncrement();
|
147
|
+
const childUUID = this.workflowUUID + "-" + funcId;
|
148
|
+
return this.#wfe.workflow(wf, { parentCtx: this, workflowUUID: childUUID }, ...args);
|
149
|
+
}
|
150
|
+
/**
|
151
|
+
* Execute a transactional function.
|
152
|
+
* The transaction is guaranteed to execute exactly once, even if the workflow is retried with the same UUID.
|
153
|
+
* If the transaction encounters a Postgres serialization error, retry it.
|
154
|
+
* If it encounters any other error, throw it.
|
155
|
+
*/
|
156
|
+
async transaction(txn, ...args) {
|
157
|
+
const config = this.#wfe.transactionConfigMap.get(txn.name);
|
158
|
+
if (config === undefined) {
|
159
|
+
throw new error_1.DBOSNotRegisteredError(txn.name);
|
160
|
+
}
|
161
|
+
const readOnly = config.readOnly ?? false;
|
162
|
+
let retryWaitMillis = 1;
|
163
|
+
const backoffFactor = 2;
|
164
|
+
const funcId = this.functionIDGetIncrement();
|
165
|
+
const span = this.#wfe.tracer.startSpan(txn.name, {
|
166
|
+
workflowUUID: this.workflowUUID,
|
167
|
+
operationName: txn.name,
|
168
|
+
runAs: this.authenticatedUser,
|
169
|
+
readOnly: readOnly,
|
170
|
+
isolationLevel: config.isolationLevel,
|
171
|
+
}, this.span);
|
172
|
+
// eslint-disable-next-line no-constant-condition
|
173
|
+
while (true) {
|
174
|
+
const wrappedTransaction = async (client) => {
|
175
|
+
// Check if this execution previously happened, returning its original result if it did.
|
176
|
+
const tCtxt = new transaction_1.TransactionContextImpl(this.#wfe.userDatabase.getName(), client, this, span, this.#wfe.logger, funcId, txn.name);
|
177
|
+
const check = await this.checkExecution(client, funcId);
|
178
|
+
if (check.output !== dbos_executor_1.dbosNull) {
|
179
|
+
tCtxt.span.setAttribute("cached", true);
|
180
|
+
tCtxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
|
181
|
+
this.#wfe.tracer.endSpan(tCtxt.span);
|
182
|
+
return check.output;
|
183
|
+
}
|
184
|
+
// TODO: record snapshot information in result buffer.
|
185
|
+
// Flush the result buffer, setting a guard to block concurrent executions with the same UUID.
|
186
|
+
this.guardOperation(funcId, check.txn_snapshot);
|
187
|
+
if (!readOnly) {
|
188
|
+
await this.flushResultBuffer(client);
|
189
|
+
}
|
190
|
+
// Execute the user's transaction.
|
191
|
+
const result = await txn(tCtxt, ...args);
|
192
|
+
// Record the execution, commit, and return.
|
193
|
+
if (readOnly) {
|
194
|
+
// Buffer the output of read-only transactions instead of synchronously writing it.
|
195
|
+
const guardOutput = {
|
196
|
+
output: result,
|
197
|
+
txn_snapshot: check.txn_snapshot,
|
198
|
+
};
|
199
|
+
this.resultBuffer.set(funcId, guardOutput);
|
200
|
+
}
|
201
|
+
else {
|
202
|
+
// Synchronously record the output of write transactions and obtain the transaction ID.
|
203
|
+
const pg_txn_id = await this.recordGuardedOutput(client, funcId, result);
|
204
|
+
tCtxt.span.setAttribute("transaction_id", pg_txn_id);
|
205
|
+
this.resultBuffer.clear();
|
206
|
+
}
|
207
|
+
return result;
|
208
|
+
};
|
209
|
+
try {
|
210
|
+
const result = await this.#wfe.userDatabase.transaction(wrappedTransaction, config);
|
211
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
212
|
+
return result;
|
213
|
+
}
|
214
|
+
catch (err) {
|
215
|
+
if (this.#wfe.userDatabase.isRetriableTransactionError(err)) {
|
216
|
+
// serialization_failure in PostgreSQL
|
217
|
+
span.addEvent("TXN SERIALIZATION FAILURE", { retryWaitMillis });
|
218
|
+
// Retry serialization failures.
|
219
|
+
await (0, utils_1.sleep)(retryWaitMillis);
|
220
|
+
retryWaitMillis *= backoffFactor;
|
221
|
+
continue;
|
222
|
+
}
|
223
|
+
// Record and throw other errors.
|
224
|
+
const e = err;
|
225
|
+
await this.#wfe.userDatabase.transaction(async (client) => {
|
226
|
+
await this.flushResultBuffer(client);
|
227
|
+
await this.recordGuardedError(client, funcId, e);
|
228
|
+
}, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
|
229
|
+
this.resultBuffer.clear();
|
230
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
|
231
|
+
throw err;
|
232
|
+
}
|
233
|
+
finally {
|
234
|
+
this.#wfe.tracer.endSpan(span);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
}
|
238
|
+
/**
|
239
|
+
* Execute a communicator function.
|
240
|
+
* If it encounters any error, retry according to its configured retry policy until the maximum number of attempts is reached, then throw an DBOSError.
|
241
|
+
* The communicator may execute many times, but once it is complete, it will not re-execute.
|
242
|
+
*/
|
243
|
+
async external(commFn, ...args) {
|
244
|
+
const commConfig = this.#wfe.communicatorConfigMap.get(commFn.name);
|
245
|
+
if (commConfig === undefined) {
|
246
|
+
throw new error_1.DBOSNotRegisteredError(commFn.name);
|
247
|
+
}
|
248
|
+
const funcID = this.functionIDGetIncrement();
|
249
|
+
const span = this.#wfe.tracer.startSpan(commFn.name, {
|
250
|
+
workflowUUID: this.workflowUUID,
|
251
|
+
operationName: commFn.name,
|
252
|
+
runAs: this.authenticatedUser,
|
253
|
+
retriesAllowed: commConfig.retriesAllowed,
|
254
|
+
intervalSeconds: commConfig.intervalSeconds,
|
255
|
+
maxAttempts: commConfig.maxAttempts,
|
256
|
+
backoffRate: commConfig.backoffRate,
|
257
|
+
}, this.span);
|
258
|
+
const ctxt = new communicator_1.CommunicatorContextImpl(this, funcID, span, this.#wfe.logger, commConfig, commFn.name);
|
259
|
+
await this.#wfe.userDatabase.transaction(async (client) => {
|
260
|
+
await this.flushResultBuffer(client);
|
261
|
+
}, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
|
262
|
+
this.resultBuffer.clear();
|
263
|
+
// Check if this execution previously happened, returning its original result if it did.
|
264
|
+
const check = await this.#wfe.systemDatabase.checkOperationOutput(this.workflowUUID, ctxt.functionID);
|
265
|
+
if (check !== dbos_executor_1.dbosNull) {
|
266
|
+
ctxt.span.setAttribute("cached", true);
|
267
|
+
ctxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
|
268
|
+
this.#wfe.tracer.endSpan(ctxt.span);
|
269
|
+
return check;
|
270
|
+
}
|
271
|
+
// Execute the communicator function. If it throws an exception, retry with exponential backoff.
|
272
|
+
// After reaching the maximum number of retries, throw an DBOSError.
|
273
|
+
let result = dbos_executor_1.dbosNull;
|
274
|
+
let err = dbos_executor_1.dbosNull;
|
275
|
+
if (ctxt.retriesAllowed) {
|
276
|
+
let numAttempts = 0;
|
277
|
+
let intervalSeconds = ctxt.intervalSeconds;
|
278
|
+
while (result === dbos_executor_1.dbosNull && numAttempts++ < ctxt.maxAttempts) {
|
279
|
+
try {
|
280
|
+
result = await commFn(ctxt, ...args);
|
281
|
+
}
|
282
|
+
catch (error) {
|
283
|
+
if (numAttempts < ctxt.maxAttempts) {
|
284
|
+
// Sleep for an interval, then increase the interval by backoffRate.
|
285
|
+
await (0, utils_1.sleep)(intervalSeconds);
|
286
|
+
intervalSeconds *= ctxt.backoffRate;
|
287
|
+
}
|
288
|
+
ctxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error.message });
|
289
|
+
this.#wfe.tracer.endSpan(ctxt.span);
|
290
|
+
}
|
291
|
+
}
|
292
|
+
}
|
293
|
+
else {
|
294
|
+
try {
|
295
|
+
result = await commFn(ctxt, ...args);
|
296
|
+
}
|
297
|
+
catch (error) {
|
298
|
+
err = error;
|
299
|
+
ctxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error.message });
|
300
|
+
this.#wfe.tracer.endSpan(ctxt.span);
|
301
|
+
}
|
302
|
+
}
|
303
|
+
// `result` can only be dbosNull when the communicator timed out
|
304
|
+
if (result === dbos_executor_1.dbosNull) {
|
305
|
+
// Record the error, then throw it.
|
306
|
+
err = err === dbos_executor_1.dbosNull ? new error_1.DBOSError("Communicator reached maximum retries.", 1) : err;
|
307
|
+
await this.#wfe.systemDatabase.recordOperationError(this.workflowUUID, ctxt.functionID, err);
|
308
|
+
ctxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
|
309
|
+
this.#wfe.tracer.endSpan(ctxt.span);
|
310
|
+
throw err;
|
311
|
+
}
|
312
|
+
else {
|
313
|
+
// Record the execution and return.
|
314
|
+
await this.#wfe.systemDatabase.recordOperationOutput(this.workflowUUID, ctxt.functionID, result);
|
315
|
+
ctxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
|
316
|
+
this.#wfe.tracer.endSpan(ctxt.span);
|
317
|
+
return result;
|
318
|
+
}
|
319
|
+
}
|
320
|
+
/**
|
321
|
+
* Send a message to a workflow identified by a UUID.
|
322
|
+
* The message can optionally be tagged with a topic.
|
323
|
+
*/
|
324
|
+
async send(destinationUUID, message, topic) {
|
325
|
+
const functionID = this.functionIDGetIncrement();
|
326
|
+
await this.#wfe.userDatabase.transaction(async (client) => {
|
327
|
+
await this.flushResultBuffer(client);
|
328
|
+
}, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
|
329
|
+
this.resultBuffer.clear();
|
330
|
+
await this.#wfe.systemDatabase.send(this.workflowUUID, functionID, destinationUUID, message, topic);
|
331
|
+
}
|
332
|
+
/**
|
333
|
+
* Consume and return the oldest unconsumed message sent to your UUID.
|
334
|
+
* If a topic is specified, retrieve the oldest message tagged with that topic.
|
335
|
+
* Otherwise, retrieve the oldest message with no topic.
|
336
|
+
*/
|
337
|
+
async recv(topic, timeoutSeconds = dbos_executor_1.DBOSExecutor.defaultNotificationTimeoutSec) {
|
338
|
+
const functionID = this.functionIDGetIncrement();
|
339
|
+
await this.#wfe.userDatabase.transaction(async (client) => {
|
340
|
+
await this.flushResultBuffer(client);
|
341
|
+
}, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
|
342
|
+
this.resultBuffer.clear();
|
343
|
+
return this.#wfe.systemDatabase.recv(this.workflowUUID, functionID, topic, timeoutSeconds);
|
344
|
+
}
|
345
|
+
/**
|
346
|
+
* Emit a workflow event, represented as a key-value pair.
|
347
|
+
* Events are immutable once set.
|
348
|
+
*/
|
349
|
+
async setEvent(key, value) {
|
350
|
+
const functionID = this.functionIDGetIncrement();
|
351
|
+
await this.#wfe.userDatabase.transaction(async (client) => {
|
352
|
+
await this.flushResultBuffer(client);
|
353
|
+
}, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
|
354
|
+
this.resultBuffer.clear();
|
355
|
+
await this.#wfe.systemDatabase.setEvent(this.workflowUUID, functionID, key, value);
|
356
|
+
}
|
357
|
+
/**
|
358
|
+
* Generate a proxy object for the provided class that wraps direct calls (i.e. OpClass.someMethod(param))
|
359
|
+
* to use WorkflowContext.Transaction(OpClass.someMethod, param);
|
360
|
+
*/
|
361
|
+
invoke(object) {
|
362
|
+
const ops = (0, decorators_1.getRegisteredOperations)(object);
|
363
|
+
const proxy = {};
|
364
|
+
for (const op of ops) {
|
365
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
366
|
+
proxy[op.name] = op.txnConfig
|
367
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
368
|
+
? (...args) => this.transaction(op.registeredFunction, ...args)
|
369
|
+
: op.commConfig
|
370
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
371
|
+
? (...args) => this.external(op.registeredFunction, ...args)
|
372
|
+
: undefined;
|
373
|
+
}
|
374
|
+
return proxy;
|
375
|
+
}
|
376
|
+
/**
|
377
|
+
* Wait for a workflow to emit an event, then return its value.
|
378
|
+
*/
|
379
|
+
getEvent(targetUUID, key, timeoutSeconds = dbos_executor_1.DBOSExecutor.defaultNotificationTimeoutSec) {
|
380
|
+
const functionID = this.functionIDGetIncrement();
|
381
|
+
return this.#wfe.systemDatabase.getEvent(targetUUID, key, timeoutSeconds, this.workflowUUID, functionID);
|
382
|
+
}
|
383
|
+
/**
|
384
|
+
* Retrieve a handle for a workflow UUID.
|
385
|
+
*/
|
386
|
+
retrieveWorkflow(targetUUID) {
|
387
|
+
const functionID = this.functionIDGetIncrement();
|
388
|
+
return new RetrievedHandle(this.#wfe.systemDatabase, targetUUID, this.workflowUUID, functionID);
|
389
|
+
}
|
390
|
+
}
|
391
|
+
exports.WorkflowContextImpl = WorkflowContextImpl;
|
392
|
+
/**
|
393
|
+
* The handle returned when invoking a workflow with DBOSExecutor.workflow
|
394
|
+
*/
|
395
|
+
class InvokedHandle {
|
396
|
+
systemDatabase;
|
397
|
+
workflowPromise;
|
398
|
+
workflowUUID;
|
399
|
+
workflowName;
|
400
|
+
callerUUID;
|
401
|
+
callerFunctionID;
|
402
|
+
constructor(systemDatabase, workflowPromise, workflowUUID, workflowName, callerUUID, callerFunctionID) {
|
403
|
+
this.systemDatabase = systemDatabase;
|
404
|
+
this.workflowPromise = workflowPromise;
|
405
|
+
this.workflowUUID = workflowUUID;
|
406
|
+
this.workflowName = workflowName;
|
407
|
+
this.callerUUID = callerUUID;
|
408
|
+
this.callerFunctionID = callerFunctionID;
|
409
|
+
}
|
410
|
+
getWorkflowUUID() {
|
411
|
+
return this.workflowUUID;
|
412
|
+
}
|
413
|
+
async getStatus() {
|
414
|
+
return this.systemDatabase.getWorkflowStatus(this.workflowUUID, this.callerUUID, this.callerFunctionID);
|
415
|
+
}
|
416
|
+
async getResult() {
|
417
|
+
return this.workflowPromise;
|
418
|
+
}
|
419
|
+
}
|
420
|
+
exports.InvokedHandle = InvokedHandle;
|
421
|
+
/**
|
422
|
+
* The handle returned when retrieving a workflow with DBOSExecutor.retrieve
|
423
|
+
*/
|
424
|
+
class RetrievedHandle {
|
425
|
+
systemDatabase;
|
426
|
+
workflowUUID;
|
427
|
+
callerUUID;
|
428
|
+
callerFunctionID;
|
429
|
+
constructor(systemDatabase, workflowUUID, callerUUID, callerFunctionID) {
|
430
|
+
this.systemDatabase = systemDatabase;
|
431
|
+
this.workflowUUID = workflowUUID;
|
432
|
+
this.callerUUID = callerUUID;
|
433
|
+
this.callerFunctionID = callerFunctionID;
|
434
|
+
}
|
435
|
+
getWorkflowUUID() {
|
436
|
+
return this.workflowUUID;
|
437
|
+
}
|
438
|
+
async getStatus() {
|
439
|
+
return await this.systemDatabase.getWorkflowStatus(this.workflowUUID, this.callerUUID, this.callerFunctionID);
|
440
|
+
}
|
441
|
+
async getResult() {
|
442
|
+
return await this.systemDatabase.getWorkflowResult(this.workflowUUID);
|
443
|
+
}
|
444
|
+
}
|
445
|
+
exports.RetrievedHandle = RetrievedHandle;
|
446
|
+
//# sourceMappingURL=workflow.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/workflow.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# DBOS Hello
|
2
|
+
|
3
|
+
This is a [DBOS app](https://docs.dbos.dev/) bootstrapped with `dbos init`.
|
4
|
+
|
5
|
+
## Getting Started
|
6
|
+
|
7
|
+
First, start the database.
|
8
|
+
DBOS workflow works with any Postgres database, but to make things easier, we've provided a nifty script that starts Postgres locally in a Docker container and creates a database:
|
9
|
+
|
10
|
+
```bash
|
11
|
+
export PGPASSWORD=dbos
|
12
|
+
./start_postgres_docker.sh
|
13
|
+
```
|
14
|
+
|
15
|
+
Then, create some database tables.
|
16
|
+
In this quickstart, we use [knex.js](https://knexjs.org/) to manage database migrations.
|
17
|
+
Run our provided migration to create a database table:
|
18
|
+
|
19
|
+
```bash
|
20
|
+
npx knex migrate:latest
|
21
|
+
```
|
22
|
+
|
23
|
+
Next, build and run the app:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
npm run build
|
27
|
+
npx dbos start
|
28
|
+
```
|
29
|
+
|
30
|
+
Finally, curl the server to see that it's working!
|
31
|
+
|
32
|
+
```bash
|
33
|
+
curl http://localhost:3000/greeting/dbos
|
34
|
+
```
|
35
|
+
|
36
|
+
You can add more functionality to the app by modifying `src/operations.ts`, then re-building and re-starting it.
|
37
|
+
We can help you get started in our [programming quickstart](https://docs.dbos.dev/getting-started/quickstart-programming-1).
|
38
|
+
|
39
|
+
## Learn More
|
40
|
+
|
41
|
+
To learn more about DBOS, take a look at [our documentation](https://docs.dbos.dev/) or our [source code](https://github.com/dbos-inc/dbos-sdk).
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# To enable auto-completion and validation for this file in VSCode, install the RedHat YAML extension
|
2
|
+
# https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml
|
3
|
+
|
4
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/dbos-inc/dbos-sdk/main/dbos-config.schema.json
|
5
|
+
|
6
|
+
database:
|
7
|
+
hostname: 'localhost'
|
8
|
+
port: 5432
|
9
|
+
username: 'postgres'
|
10
|
+
password: ${PGPASSWORD}
|
11
|
+
user_database: 'hello'
|
12
|
+
system_database: 'hello_systemdb'
|
13
|
+
connectionTimeoutMillis: 3000
|
14
|
+
user_dbclient: 'knex'
|
15
|
+
version: "1.0"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
// knexfile.ts
|
2
|
+
|
3
|
+
import { Knex } from 'knex';
|
4
|
+
import { parseConfigFile } from '@dbos-inc/dbos-sdk/dist/src/dbos-runtime/config'
|
5
|
+
import { DBOSConfig } from '@dbos-inc/dbos-sdk/dist/src/dbos-executor';
|
6
|
+
|
7
|
+
const [dbosConfig, ]: [DBOSConfig, unknown] = parseConfigFile();
|
8
|
+
|
9
|
+
const config: Knex.Config = {
|
10
|
+
client: 'pg',
|
11
|
+
connection: {
|
12
|
+
host: dbosConfig.poolConfig.host,
|
13
|
+
user: dbosConfig.poolConfig.user,
|
14
|
+
password: dbosConfig.poolConfig.password,
|
15
|
+
database: dbosConfig.poolConfig.database,
|
16
|
+
ssl: dbosConfig.poolConfig.ssl,
|
17
|
+
},
|
18
|
+
migrations: {
|
19
|
+
directory: './migrations'
|
20
|
+
}
|
21
|
+
};
|
22
|
+
|
23
|
+
export default config;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Knex } from "knex";
|
2
|
+
|
3
|
+
export async function up(knex: Knex): Promise<void> {
|
4
|
+
return knex.schema.createTable('dbos_hello', table => {
|
5
|
+
table.text('name').primary();
|
6
|
+
table.integer('greet_count').defaultTo(0);
|
7
|
+
});
|
8
|
+
}
|
9
|
+
|
10
|
+
export async function down(knex: Knex): Promise<void> {
|
11
|
+
return knex.schema.dropTable('dbos_hello');
|
12
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"name": "dbos-hello",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"scripts": {
|
5
|
+
"build": "tsc",
|
6
|
+
"test": "npx knex migrate:rollback && npx knex migrate:up && jest"
|
7
|
+
},
|
8
|
+
"devDependencies": {
|
9
|
+
"@types/jest": "^29.5.5",
|
10
|
+
"@types/supertest": "^2.0.14",
|
11
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
12
|
+
"jest": "^29.7.0",
|
13
|
+
"supertest": "^6.3.3",
|
14
|
+
"ts-jest": "^29.1.1",
|
15
|
+
"typescript": "^5.2.2"
|
16
|
+
},
|
17
|
+
"dependencies": {
|
18
|
+
"@dbos-inc/dbos-sdk": "../..",
|
19
|
+
"ts-node": "^10.9.1"
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { TestingRuntime, createTestingRuntime } from "@dbos-inc/dbos-sdk";
|
2
|
+
import { Hello, dbos_hello } from "./operations";
|
3
|
+
import request from "supertest";
|
4
|
+
|
5
|
+
describe("operations-test", () => {
|
6
|
+
let testRuntime: TestingRuntime;
|
7
|
+
|
8
|
+
beforeAll(async () => {
|
9
|
+
testRuntime = await createTestingRuntime([Hello]);
|
10
|
+
});
|
11
|
+
|
12
|
+
afterAll(async () => {
|
13
|
+
await testRuntime.destroy();
|
14
|
+
});
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Test the transaction.
|
18
|
+
*/
|
19
|
+
test("test-transaction", async () => {
|
20
|
+
const res = await testRuntime.invoke(Hello).helloTransaction("dbos");
|
21
|
+
expect(res).toMatch("Hello, dbos! You have been greeted");
|
22
|
+
|
23
|
+
// Check the greet count.
|
24
|
+
const rows = await testRuntime.queryUserDB<dbos_hello>("SELECT * FROM dbos_hello WHERE name=$1", "dbos");
|
25
|
+
expect(rows[0].greet_count).toBe(1);
|
26
|
+
});
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Test the HTTP endpoint.
|
30
|
+
*/
|
31
|
+
test("test-endpoint", async () => {
|
32
|
+
const res = await request(testRuntime.getHandlersCallback()).get(
|
33
|
+
"/greeting/dbos"
|
34
|
+
);
|
35
|
+
expect(res.statusCode).toBe(200);
|
36
|
+
expect(res.text).toMatch("Hello, dbos! You have been greeted");
|
37
|
+
});
|
38
|
+
});
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { TransactionContext, Transaction, GetApi, ArgSource, ArgSources } from '@dbos-inc/dbos-sdk'
|
2
|
+
import { Knex } from 'knex';
|
3
|
+
|
4
|
+
// The schema of the database table used in this example.
|
5
|
+
export interface dbos_hello {
|
6
|
+
name: string;
|
7
|
+
greet_count: number;
|
8
|
+
}
|
9
|
+
|
10
|
+
export class Hello {
|
11
|
+
|
12
|
+
@GetApi('/greeting/:user') // Serve this function from HTTP GET requests to the /greeting endpoint with 'user' as a path parameter
|
13
|
+
@Transaction() // Run this function as a database transaction
|
14
|
+
static async helloTransaction(ctxt: TransactionContext<Knex>, @ArgSource(ArgSources.URL) user: string) {
|
15
|
+
// Retrieve and increment the number of times this user has been greeted.
|
16
|
+
const query = "INSERT INTO dbos_hello (name, greet_count) VALUES (?, 1) ON CONFLICT (name) DO UPDATE SET greet_count = dbos_hello.greet_count + 1 RETURNING greet_count;"
|
17
|
+
const { rows } = await ctxt.client.raw(query, [user]) as { rows: dbos_hello[] };
|
18
|
+
const greet_count = rows[0].greet_count;
|
19
|
+
return `Hello, ${user}! You have been greeted ${greet_count} times.\n`;
|
20
|
+
}
|
21
|
+
}
|