Skip to content

Commit c63d09b

Browse files
devhawkHarry Pierson
and
Harry Pierson
authored
TT DBG Quickstart (#99)
Co-authored-by: Harry Pierson <[email protected]>
1 parent 38f377f commit c63d09b

6 files changed

+219
-1
lines changed
Loading
Loading
19.8 KB
Loading
108 KB
Loading

docs/getting-started/quickstart-programming.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
sidebar_position: 3
2+
sidebar_position: 2
33
title: Programming Quickstart
44
---
55

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
---
2+
sidebar_position: 3
3+
title: Time Travel Debugger Quickstart
4+
---
5+
6+
Now that we've learned a little about programming DBOS, let's learn how to use the DBOS Time Travel Debugger!
7+
8+
This tutorial assumes you have [Visual Studio Code](https://code.visualstudio.com/) installed.
9+
Please see the VS Code documentation for [installation instructions](https://code.visualstudio.com/docs/setup/setup-overview) if necessary.
10+
11+
:::info
12+
If you're not a VS Code user, there is an advanced tutorial for [Time Travel Debugging with DBOS CLI](../cloud-tutorials/timetravel-debugging#time-travel-with-dbos-sdk-cli-non-vs-code-users).
13+
:::
14+
15+
Additionally, this tutorial builds on the [DBOS Quickstart](./quickstart).
16+
For convenience, we recommend [creating a DBOS Cloud account](./quickstart#deploying-to-dbos-cloud) and
17+
[provisioning a DBOS Cloud database instance](./quickstart#provisioning-a-cloud-database-instance) before starting this tutorial.
18+
19+
### Installing the DBOS Time Travel Debugging VS Code Extension
20+
21+
Before we use the DBOS Time Travel debugger, we need to install its VS Code extension.
22+
23+
To install the extension, navigate to the [extension's web page](https://marketplace.visualstudio.com/items?itemName=dbos-inc.dbos-ttdbg) and press the "Install" button.
24+
This will launch VS Code and open the DBOS Time Travel Debugger extension page inside the IDE.
25+
From there, select the "Install" button to install the extension.
26+
27+
![Installing the DBOS Extension](./assets//ttdbg-install.png)
28+
29+
:::info
30+
You can also install the extension by opening the [Extension Marketplace](https://code.visualstudio.com/docs/editor/extension-marketplace)
31+
inside VS Code (default keybinding: Ctrl+Shift+X / ⇧⌘X) and searching for "DBOS".
32+
:::
33+
34+
### Deploy the Programming Quickstart App to DBOS Cloud
35+
36+
In this tutorial, you will time travel debug the `greeting-emails` application you built in the [Programming Quickstart](./quickstart-programming).
37+
38+
If you finished that tutorial, remove the sleep logic from `GreetingWorkflow`.
39+
We're not going to need that sleep code for this tutorial.
40+
41+
If you did not finished the Programming Quickstart, create a new DBOS application using `@dbos-inc/create`.
42+
43+
```
44+
npx -y @dbos-inc/create -n <app-name>
45+
```
46+
47+
And replace the logic in `src/operations.ts` with the following.
48+
49+
```ts
50+
import {
51+
TransactionContext, Transaction,
52+
HandlerContext, GetApi,
53+
CommunicatorContext, Communicator,
54+
WorkflowContext, Workflow,
55+
} from "@dbos-inc/dbos-sdk";
56+
import { Knex } from "knex";
57+
58+
export class Greetings {
59+
@Communicator()
60+
static async SendGreetingEmail(ctxt: CommunicatorContext, friend: string, content: string) {
61+
ctxt.logger.info(`Sending email "${content}" to ${friend}...`);
62+
// Code omitted for simplicity
63+
ctxt.logger.info("Email sent!");
64+
}
65+
66+
@Transaction()
67+
static async InsertGreeting(ctxt: TransactionContext<Knex>, friend: string, content: string) {
68+
await ctxt.client.raw(
69+
"INSERT INTO dbos_greetings (greeting_name, greeting_note_content) VALUES (?, ?)",
70+
[friend, content]
71+
);
72+
}
73+
74+
@Workflow()
75+
@GetApi("/greeting/:friend")
76+
static async GreetingWorkflow(ctxt: WorkflowContext, friend: string) {
77+
const noteContent = `Thank you for being awesome, ${friend}!`;
78+
await ctxt.invoke(Greetings).SendGreetingEmail(friend, noteContent);
79+
await ctxt.invoke(Greetings).InsertGreeting(friend, noteContent);
80+
ctxt.logger.info(`Greeting sent to ${friend}!`);
81+
return noteContent;
82+
}
83+
}
84+
```
85+
86+
Next, we are going to deploy this application to DBOS Cloud.
87+
Currently, Time Travel Debugging is only supported for applications that have been deployed to DBOS Cloud.
88+
89+
If you finished the [DBOS quickstart](./quickstart), you should already have a DBOS Cloud account and database instance.
90+
If you didn't finish the [Deploying to DBOS Cloud](./quickstart#deploying-to-dbos-cloud) section of that tutorial,
91+
please create an account and provision a cloud database instance by running the `npx dbos-cloud` commands shown below from project's root folder.
92+
Note, it can take up to 5 minutes to provision a database instance
93+
94+
```
95+
npx dbos-cloud register -u <username>
96+
npx dbos-cloud db provision <database-instance-name> -U <database-username>
97+
```
98+
99+
You can then deploy the app to DBOS Cloud by executing these commands from project's root folder:
100+
101+
```
102+
npx dbos-cloud app register -d <database-instance-name>
103+
npx dbos-cloud app deploy
104+
```
105+
106+
:::info
107+
DBOS Cloud database instances can host multiple application databases.
108+
Even if you deployed the DBOS quickstart app, you can also deploy the `greeting-emails` app using the same database instance.
109+
:::
110+
111+
When complete, the `npx dbos-cloud app deploy` command will print your application's URL to the console.
112+
The URL will be formatted like: `https://<username>-greeting-emails.cloud.dbos.dev/`.
113+
Visit `https://<username>-greeting-emails.cloud.dbos.dev/greeting/dbos` in your browser a few times to generate data that we can use to demonstrate the time travel debugger.
114+
115+
### Time Travel Debugging Your Cloud Application
116+
117+
After you have installed the DBOS VS Code extension and deployed the app to DBOS Cloud, open up the project folder in VS Code then open the `src/operations.ts` file in the editor.
118+
Set a breakpoint at the top of each of the functions in the `operations.ts` file: `GreetingWorkflow`, `InsertGreeting`, `SendGreetingEmail`.
119+
To set a breakpoint in VS Code, position the cursor on desired line and press `F9`.
120+
121+
Notice there is a Time Travel Debug CodeLens attached to each function in the app.
122+
This CodeLens is automatically attached to every DBOS Workflow, Transaction and Communicator function in a DBOS application.
123+
Click on the CodeLens attached to the `GreetingWorkflow` function.
124+
125+
![DBOS Time Travel Extension CodeLens Screenshot](./assets/ttdbg-code-lens.png)
126+
127+
After you click on the CodeLens, you will given a list of workflow IDs of that function to choose from.
128+
129+
![DBOS Time Travel Extension workflow picker](../cloud-tutorials/assets/ttdbg-wfid-quick-pick.png)
130+
131+
After you select a workflow ID, the DBOS Time Travel Debugger will launch the DBOS debug runtime and VS Code TypeScript debugger.
132+
The workflow will start executing and break on the breakpoint you set at the top of the `GreetingWorkflow` method.
133+
134+
![DBOS Time Travel Extension breakpoint](./assets/ttdbg-breakpoint-1.png)
135+
136+
The debugging experience for your DBOS application is similar to debugging any other
137+
[Node.JS application](https://code.visualstudio.com/docs/nodejs/nodejs-debugging) in VS Code.
138+
You can [set breakpoints](https://code.visualstudio.com/docs/editor/debugging#_breakpoints),
139+
[inspect variables](https://code.visualstudio.com/docs/editor/debugging#_data-inspection) and
140+
[step through your code](https://code.visualstudio.com/docs/editor/debugging#_debug-actions) as you would expect.
141+
However, there is one significant difference that you will notice if you press the Continue (F5) in the debugger.
142+
143+
![DBOS Time Travel Extension breakpoint](./assets/ttdbg-breakpoint-2.png)
144+
145+
Even though you set a breakpoint in the `SendGreetingEmail` function, it did not get hit.
146+
Instead, the debugger stopped at the breakpoint at the `InsertGreeting` function.
147+
This is by design.
148+
[Communicators](../tutorials/communicator-tutorial.md) are used for code with non-idempotent side effects, such as sending an email to a user.
149+
When debugging, DBOS skips communicators to avoid these side effects.
150+
151+
### Debugging Your Updated Application
152+
153+
The Time Travel Debugger executes your DBOS application locally working against a snapshot of your DBOS Cloud database _as it existed at the time the selected workflow actually ran_.
154+
Unfortunately, the programming quickstart application only writes data to the database, it does not read it.
155+
This means the execution of `GreetingWorkflow` is identical regardless which workflow ID you selected to execute.
156+
Let's modify the code to read some state from the database and see how this updated code interacts with existing workflow executions stored in DBOS Cloud.
157+
158+
Update `InsertGreeting` function to retrieve how many greetings the friend has received before and after the new greeting is added.
159+
160+
```ts
161+
@Transaction()
162+
static async InsertGreeting(ctxt: TransactionContext<Knex>, friend: string, content: string) {
163+
const before = await ctxt.client.raw(
164+
"SELECT count(*) FROM dbos_greetings WHERE greeting_name = ?",
165+
[friend]
166+
);
167+
ctxt.logger.info(`before count ${before.rows[0].count}`);
168+
169+
await ctxt.client.raw(
170+
"INSERT INTO dbos_greetings (greeting_name, greeting_note_content) VALUES (?, ?)",
171+
[friend, content]
172+
);
173+
174+
const after = await ctxt.client.raw(
175+
"SELECT count(*) FROM dbos_greetings WHERE greeting_name = ?",
176+
[friend]
177+
);
178+
ctxt.logger.info(`after count ${after.rows[0].count}`);
179+
}
180+
```
181+
182+
Now, when we click the `GreetingWorkflow` CodeLens, the workflow execution we select will affect the log output.
183+
If we select the oldest execution, we get output that looks like this.
184+
185+
```
186+
2024-03-22 23:00:53 [info]: Running in debug mode!
187+
2024-03-22 23:00:53 [info]: Debugging mode proxy: localhost:2345
188+
2024-03-22 23:00:53 [info]: Workflow executor initialized
189+
2024-03-22 23:00:57 [info]: before count 0
190+
2024-03-22 23:00:57 [info]: after count 1
191+
2024-03-22 23:01:01 [info]: Greeting sent to friend!
192+
```
193+
194+
But if we select a later execution, we get different output.
195+
196+
```
197+
2024-03-22 23:03:40 [info]: Running in debug mode!
198+
2024-03-22 23:03:40 [info]: Debugging mode proxy: localhost:2345
199+
2024-03-22 23:03:40 [info]: Workflow executor initialized
200+
2024-03-22 23:03:46 [info]: before count 2
201+
2024-03-22 23:03:47 [info]: after count 3
202+
2024-03-22 23:03:47 [info]: Greeting sent to friend!
203+
```
204+
205+
To clarify what has happened here, you modified the InsertGreeting function to retrieve database state and log it.
206+
Then, you executed that updated code in the Time Travel Debugger working against _past database state_.
207+
Note, this worked even though your local code is different from the code running in DBOS Cloud!
208+
209+
:::warning
210+
When time travel debugging, you can freely add read queries to your application and observe their results when run against past database state.
211+
This state can be viewed via the logger as described above or via VS Code's variables window.
212+
However, you cannot change code that updates database state (i.e. insert/delete/update SQL statements) or change the value returned from
213+
a workflow or transaction function.
214+
:::
215+
216+
Now that you know the basics of DBOS Time Travel Debugging, please check out our [tutorials](../category/dbos-sdk-tutorials).
217+
To learn more about the Time Travel Debugger, check out our Time Travel Debugger [tutorial](../cloud-tutorials/timetravel-debugging)
218+
and [reference](../api-reference/time-travel-debugger).

0 commit comments

Comments
 (0)