From 7cd5e036fde0a9556c07f0aa0faeef735aadccb4 Mon Sep 17 00:00:00 2001 From: Peter Kraft Date: Fri, 21 Feb 2025 12:00:13 -0800 Subject: [PATCH 1/6] start rewrite --- .../development => self-hosting}/self-hosting.md | 5 ++--- docusaurus.config.js | 6 +++++- sidebars.js | 10 ++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) rename docs/{typescript/tutorials/development => self-hosting}/self-hosting.md (97%) diff --git a/docs/typescript/tutorials/development/self-hosting.md b/docs/self-hosting/self-hosting.md similarity index 97% rename from docs/typescript/tutorials/development/self-hosting.md rename to docs/self-hosting/self-hosting.md index d3f14a665..8435f8a82 100644 --- a/docs/typescript/tutorials/development/self-hosting.md +++ b/docs/self-hosting/self-hosting.md @@ -1,7 +1,6 @@ --- -sidebar_position: 40 -title: Self-Hosting -description: Learn how to self-host DBOS Transact applications +sidebar_position: 1 +title: Self-Hosting DBOS Apps --- You can run DBOS Transact applications anywhere with [`npx dbos start`](../../reference/tools/cli.md#npx-dbos-start) as long as they have a Postgres database to connect to. diff --git a/docusaurus.config.js b/docusaurus.config.js index 1763d9d7a..a6ec5eb68 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -128,7 +128,11 @@ const config = { }, { from: '/typescript/tutorials/self-hosting', - to: '/typescript/tutorials/development/self-hosting', + to: '/self-hosting', + }, + { + from: '/typescript/tutorials/development/self-hosting', + to: '/self-hosting', }, { from: '/typescript/tutorials/using-libraries', diff --git a/sidebars.js b/sidebars.js index 8c8c576b8..a41646edc 100644 --- a/sidebars.js +++ b/sidebars.js @@ -59,6 +59,16 @@ const sidebars = { } ], }, + { + type: 'category', + label: 'Self-Hosting', + items: [ + { + type: 'autogenerated', + dirName: 'self-hosting', + } + ], + }, { type: 'category', label: 'Integrations', From 77fa2e354965debc1190922ad83cef2b697ea774 Mon Sep 17 00:00:00 2001 From: Peter Kraft Date: Fri, 21 Feb 2025 14:19:40 -0800 Subject: [PATCH 2/6] self hosting --- docs/self-hosting/self-hosting.md | 69 ++++++++++++++----------------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/docs/self-hosting/self-hosting.md b/docs/self-hosting/self-hosting.md index 8435f8a82..ae56a071a 100644 --- a/docs/self-hosting/self-hosting.md +++ b/docs/self-hosting/self-hosting.md @@ -3,12 +3,36 @@ sidebar_position: 1 title: Self-Hosting DBOS Apps --- -You can run DBOS Transact applications anywhere with [`npx dbos start`](../../reference/tools/cli.md#npx-dbos-start) as long as they have a Postgres database to connect to. -This guide describes tools you can use in your hosting environment to make the most of DBOS Transact. +Because DBOS is implemented in lightweight TypeScript and Python libraries, you can run your DBOS application anywhere as long as it has a Postgres server to connect to. +This guide provides information on operating a self-hosted DBOS application. -## Admin API +## Self-Hosting On A Single Server -DBOS applications expose an admin API, fixed at one above the main DBOS application port (the main port defaults to port 3000, so the admin API defaults to port 3001). +Self-hosting a DBOS application on a single server is simple: each time you restart your application's process, it recovers all workflows that were executing before the restart (all `PENDING` workflows). + +However, it is important to be careful when upgrading your application's code. +When DBOS is launched, it computes an "application version" from a checksum of the code in your application's workflows (you can override this version through the `DBOS__APPVERSION` environment variable). +Each workflow is tagged with the version of the application that started it. +When a DBOS application starts, it does not recover workflows tagged with a different application version. +Thus, to safely recover workflows started on an older version of your code, you should start a process running that code version. + +## Self-Hosting on Multiple Servers + +When self-hosting in a distributed setting, it is important to manage workflow recovery so that when an executor crashes, restarts, or is shut down, its workflows are recovered. +You should assign each executor running a DBOS application an executor ID by setting the `DBOS__VMID` environment variable. +Each workflow is tagged with the ID of the executor that started it. +When an application with an executor ID restarts, it only recovers pending workflows assigned to that executor ID. +You can also instruct your executor to recover workflows assigned to other executor IDs through the [workflow recovery endpoint of the admin API](#workflow-recovery). + +It is also important to be careful when upgrading your application's code. +When DBOS is launched, it computes an "application version" from a checksum of the code in your application's workflows (you can override this version through the `DBOS__APPVERSION` environment variable). +Each workflow is tagged with the version of the application that started it. +When a DBOS application starts, it does not recover workflows tagged with a different application version. +To safely recover workflows started on an older version of your code, you should start a process running that code version and use the [workflow recovery endpoint of the admin API](#workflow-recovery) to instruct it to recover workflows belonging to executors that ran old versions of DBOS. + +## Admin API Reference + +DBOS applications expose an admin API on port 3001. It provides the following endpoints: ### Health Check @@ -21,10 +45,9 @@ It provides the following endpoints: ### Workflow Recovery - - **Endpoint**: `/dbos-workflow-recovery` - **Method**: POST -- **Description**: Recovers all pending workflows associated with input [executor IDs](#managing-workflow-recovery). Following our [reliability guarantees](../workflow-tutorial.md#reliability-guarantees), all workflows will resume from where they left off. Returns the UUIDs of all workflows recovered. +- **Description**: Recover all pending workflows associated with input [executor IDs](#managing-workflow-recovery). Returns the IDs of all workflows queued for recovery. - **Request Body Format**: JSON list of executors whose pending workflows to recover. - **Example**: ```json @@ -32,40 +55,8 @@ It provides the following endpoints: ``` - **Response**: - **Status Code**: 200 OK on successful recovery initiation; otherwise, appropriate error codes. - - **Body Format**: JSON list of UUIDs representing the workflows that were successfully queued for recovery. + - **Body Format**: JSON list of the IDs of workflows queued for recovery. - **Example**: ```json ["workflow-uuid-1", "workflow-uuid-2", "..."] ``` - -### Performance Metrics - -- **Endpoint**: `/dbos-perf` -- **HTTP Method**: GET -- **Description**: Provides a snapshot of the application's event loop utilization since the last request to `/dbos-perf`. Implemented using the [Node.js performance API](https://nodejs.org/api/perf_hooks.html#performanceeventlooputilizationutilization1-utilization2). -- **Response**: - - **Status Code**: 200 OK if metrics are successfully fetched; otherwise, appropriate error codes. - - **Body Format**: JSON - - **Fields**: - - `active`: Time in milliseconds the event loop has been active since the last call to `/dbos-perf`. - - `idle`: Time in milliseconds the event loop has been idle since the last call to `/dbos-perf`. - - `utilization`: The percentage of time the event loop is active. - - **Example**: - ```json - { - "active": "200", - "idle": "800", - "utilization": "0.2" - } - ``` - -## Managing Workflow Recovery - -By default, when a DBOS application starts up, it recovers all pending workflows, resuming them from where they left off following our [reliability guarantees](../workflow-tutorial.md#reliability-guarantees). -This behavior works well when you're only running a single instance of an application, as it guarantees that every time the server is restarted, it resumes all workflows from where they left off. -However, it is less ideal for a distributed setting where you're running many instances of an application on different servers. - -To manage recovery in a distributed setting, you can assign each instance of an application an executor ID by setting the `DBOS__VMID` environment variable. -This causes the application instance to associate every workflow it executes with that executor ID. -When an application instance with an executor ID restarts, it only recovers pending workflows assigned to that executor ID. -You can also instruct it to recover workflows assigned to other executor IDs through the [admin API](#managing-workflow-recovery). From e78fd95cd4d3f81f8f64af2c2203e2d02f564ff8 Mon Sep 17 00:00:00 2001 From: Peter Kraft Date: Fri, 21 Feb 2025 14:21:55 -0800 Subject: [PATCH 3/6] deactivate --- docs/self-hosting/self-hosting.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/self-hosting/self-hosting.md b/docs/self-hosting/self-hosting.md index ae56a071a..0b34d3d61 100644 --- a/docs/self-hosting/self-hosting.md +++ b/docs/self-hosting/self-hosting.md @@ -60,3 +60,11 @@ It provides the following endpoints: ```json ["workflow-uuid-1", "workflow-uuid-2", "..."] ``` + +### Deactivate + +- **Endpoint**: `/deactivate` +- **Method**: GET +- **Description**: Deactivate an executor. A deactivated executor may complete active workflows and recover `PENDING` workflows, but may not start new workflows or dequeue workflows. +- **Response**: + - **Status Code**: 200 OK if the request succeeeded; otherwise, appropriate error codes. From bcab710e1e5fec53db2b45c01d29af44144a0817 Mon Sep 17 00:00:00 2001 From: Peter Kraft Date: Fri, 21 Feb 2025 17:50:56 -0800 Subject: [PATCH 4/6] version docs --- docs/python/tutorials/workflow-tutorial.md | 17 +++++++++++++++++ docs/typescript/tutorials/workflow-tutorial.md | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/docs/python/tutorials/workflow-tutorial.md b/docs/python/tutorials/workflow-tutorial.md index ecffeb2ab..3822d1b49 100644 --- a/docs/python/tutorials/workflow-tutorial.md +++ b/docs/python/tutorials/workflow-tutorial.md @@ -253,6 +253,23 @@ async def example_workflow(friend: str): return result ``` +## Workflow Versioning and Recovery + +Because DBOS recovers workflows by re-executing them using information saved in the database, a workflow cannot safely be recovered if its code has changed since the workflow was started. +To guard against this, DBOS _versions_ applications and their workflows. +When DBOS is launched, it computes an application version from a hash of the source code of its workflows (this can be overridden by setting the `DBOS__APPVERSION` environment variable). +All workflows are tagged with the application version on which they started. +When DBOS tries to recover workflows, it only recovers workflows whose version matches the current application version. +This prevents unsafe recovery of workflows that depend on different code. + +On DBOS Cloud, when an application is redeployed, executors running old versions are retained until they have completed all workflows that started on those versions. +When self-hosting, to safely recover workflows started on an older version of your code, you should start a process running that code version. +You can also manually recover a workflow on your current version with: + +```shell +dbos workflow resume +``` + ## Workflow Management Because DBOS stores the execution state of workflows in Postgres, you can view and manage your workflows from the command line. diff --git a/docs/typescript/tutorials/workflow-tutorial.md b/docs/typescript/tutorials/workflow-tutorial.md index 064d23e48..4a459dff1 100644 --- a/docs/typescript/tutorials/workflow-tutorial.md +++ b/docs/typescript/tutorials/workflow-tutorial.md @@ -224,6 +224,23 @@ All messages are persisted to the database, so if `send` completes successfully, If you're sending a message from a workflow, DBOS guarantees exactly-once delivery because [workflows are reliable](#reliability-guarantees). If you're sending a message from normal TypeScript code, you can specify an idempotency key for `send` or use [`DBOS.withNextWorkflowID`](../reference/transactapi/dbos-class.md#assigning-workflow-ids) to guarantee exactly-once delivery. +## Workflow Versioning and Recovery + +Because DBOS recovers workflows by re-executing them using information saved in the database, a workflow cannot safely be recovered if its code has changed since the workflow was started. +To guard against this, DBOS _versions_ applications and their workflows. +When DBOS is launched, it computes an application version from a hash of the source code of its workflows (this can be overridden by setting the `DBOS__APPVERSION` environment variable). +All workflows are tagged with the application version on which they started. +When DBOS tries to recover workflows, it only recovers workflows whose version matches the current application version. +This prevents unsafe recovery of workflows that depend on different code. + +On DBOS Cloud, when an application is redeployed, executors running old versions are retained until they have completed all workflows that started on those versions. +When self-hosting, to safely recover workflows started on an older version of your code, you should start a process running that code version. +You can also manually recover a workflow on your current version with: + +```shell +npx dbos workflow resume +``` + ## Workflow Management Because DBOS stores the execution state of workflows in Postgres, you can view and manage your workflows from the command line. From 373a2a0b04b21a1482c34ba42fbad6b6b00f832d Mon Sep 17 00:00:00 2001 From: Peter Kraft Date: Mon, 24 Feb 2025 15:02:20 -0800 Subject: [PATCH 5/6] expand intro --- docs/self-hosting/self-hosting.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/self-hosting/self-hosting.md b/docs/self-hosting/self-hosting.md index 0b34d3d61..3355a77d9 100644 --- a/docs/self-hosting/self-hosting.md +++ b/docs/self-hosting/self-hosting.md @@ -3,8 +3,12 @@ sidebar_position: 1 title: Self-Hosting DBOS Apps --- -Because DBOS is implemented in lightweight TypeScript and Python libraries, you can run your DBOS application anywhere as long as it has a Postgres server to connect to. -This guide provides information on operating a self-hosted DBOS application. +Because DBOS is implemented in lightweight TypeScript and Python libraries, you can **run your DBOS application anywhere** as long as it has a Postgres server to connect to. +DBOS runs entirely inside your process, executing your workflows and recording their state in Postgres. +By default, when your process restarts, DBOS recovers all its pending workflows. +However, care must be taken when upgrading your application's code or when managing many DBOS processes at scale to ensure all your workflows are efficiently recovered. + +This guide will describe best practices for self-hosting an application that uses DBOS, explaining how to manage workflow recovery both when operating on a single server and when operating at scale. ## Self-Hosting On A Single Server From dc9c208f8c77118005554ccdf10f212979c44a94 Mon Sep 17 00:00:00 2001 From: Peter Kraft Date: Tue, 25 Feb 2025 14:02:22 -0800 Subject: [PATCH 6/6] improvements --- docs/self-hosting/self-hosting.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/self-hosting/self-hosting.md b/docs/self-hosting/self-hosting.md index 3355a77d9..61c96b726 100644 --- a/docs/self-hosting/self-hosting.md +++ b/docs/self-hosting/self-hosting.md @@ -8,18 +8,12 @@ DBOS runs entirely inside your process, executing your workflows and recording t By default, when your process restarts, DBOS recovers all its pending workflows. However, care must be taken when upgrading your application's code or when managing many DBOS processes at scale to ensure all your workflows are efficiently recovered. -This guide will describe best practices for self-hosting an application that uses DBOS, explaining how to manage workflow recovery both when operating on a single server and when operating at scale. +This guide will describe best practices for self-hosting an application that uses the open-source DBOS libraries, explaining how to manage workflow recovery both when operating on a single server and when operating at scale. ## Self-Hosting On A Single Server Self-hosting a DBOS application on a single server is simple: each time you restart your application's process, it recovers all workflows that were executing before the restart (all `PENDING` workflows). -However, it is important to be careful when upgrading your application's code. -When DBOS is launched, it computes an "application version" from a checksum of the code in your application's workflows (you can override this version through the `DBOS__APPVERSION` environment variable). -Each workflow is tagged with the version of the application that started it. -When a DBOS application starts, it does not recover workflows tagged with a different application version. -Thus, to safely recover workflows started on an older version of your code, you should start a process running that code version. - ## Self-Hosting on Multiple Servers When self-hosting in a distributed setting, it is important to manage workflow recovery so that when an executor crashes, restarts, or is shut down, its workflows are recovered. @@ -28,11 +22,16 @@ Each workflow is tagged with the ID of the executor that started it. When an application with an executor ID restarts, it only recovers pending workflows assigned to that executor ID. You can also instruct your executor to recover workflows assigned to other executor IDs through the [workflow recovery endpoint of the admin API](#workflow-recovery). -It is also important to be careful when upgrading your application's code. +## Managing Application versions + +When self-hosting, it is important to be careful when upgrading your application's code. When DBOS is launched, it computes an "application version" from a checksum of the code in your application's workflows (you can override this version through the `DBOS__APPVERSION` environment variable). Each workflow is tagged with the version of the application that started it. -When a DBOS application starts, it does not recover workflows tagged with a different application version. -To safely recover workflows started on an older version of your code, you should start a process running that code version and use the [workflow recovery endpoint of the admin API](#workflow-recovery) to instruct it to recover workflows belonging to executors that ran old versions of DBOS. +To prevent code compatibility issues, DBOS does not attempt to recover workflows tagged with a different application version. + +To safely recover workflows started on an older version of your code, you should start a process running that code version. +If self-hosting on a single server, that process will automatically recover all pending workflows of that code version. +If self-hosting in a distributed setting, you should use the [workflow recovery endpoint of the admin API](#workflow-recovery) to instruct that process to recover workflows belonging to executors that ran old code versions. ## Admin API Reference