@dbos-inc/create 1.31.14-preview.g31029d25df → 1.31.16-preview
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/hello/README.md +11 -30
- package/templates/hello/package.json +1 -5
- package/templates/hello/src/operations.test.ts +7 -8
- package/templates/hello/src/operations.ts +11 -13
- package/templates/{hello-v2 → hello-contexts}/README.md +30 -9
- package/templates/{hello-v2 → hello-contexts}/package.json +5 -1
- package/templates/{hello-v2 → hello-contexts}/src/operations.test.ts +8 -7
- package/templates/{hello-v2 → hello-contexts}/src/operations.ts +13 -11
- package/templates/hello-drizzle/README.md +6 -6
- package/templates/hello-drizzle/package.json +2 -2
- package/templates/hello-drizzle/src/operations.test.ts +7 -8
- package/templates/hello-drizzle/src/operations.ts +7 -7
- package/templates/hello-express/README.md +10 -8
- package/templates/hello-express/dbos-config.yaml +1 -1
- package/templates/hello-express/src/main.test.ts +1 -1
- package/templates/hello-express/src/main.ts +86 -3
- package/templates/hello-nextjs/README.md +21 -12
- package/templates/hello-nextjs/src/actions/dbosWorkflow.tsx +24 -0
- package/templates/hello-nextjs/src/app/crash/route.ts +8 -0
- package/templates/hello-nextjs/src/app/page.tsx +10 -2
- package/templates/hello-nextjs/src/app/step/[slug]/route.ts +15 -0
- package/templates/hello-nextjs/src/app/tasks/[slug]/route.ts +18 -0
- package/templates/hello-nextjs/src/components/client/BackGroundTask.tsx +180 -0
- package/templates/hello-prisma/README.md +8 -8
- package/templates/hello-prisma/src/operations.test.ts +6 -6
- package/templates/hello-prisma/src/operations.ts +7 -7
- package/templates/hello-typeorm/README.md +8 -8
- package/templates/hello-typeorm/src/operations.test.ts +7 -6
- package/templates/hello-typeorm/src/operations.ts +7 -7
- package/templates/hello-express/src/operations.ts +0 -81
- /package/templates/{hello-v2 → hello-contexts}/.vscode/extensions.json +0 -0
- /package/templates/{hello-v2 → hello-contexts}/.vscode/launch.json +0 -0
- /package/templates/{hello-v2 → hello-contexts}/.vscode/tasks.json +0 -0
- /package/templates/{hello-v2 → hello-contexts}/dbos-config.yaml +0 -0
- /package/templates/{hello-v2 → hello-contexts}/eslint.config.js +0 -0
- /package/templates/{hello-v2 → hello-contexts}/gitignore.template +0 -0
- /package/templates/{hello-v2 → hello-contexts}/jest.config.js +0 -0
- /package/templates/{hello-v2 → hello-contexts}/knexfile.js +0 -0
- /package/templates/{hello-v2 → hello-contexts}/migrations/20240212161006_create_dbos_hello_tables.js +0 -0
- /package/templates/{hello-v2 → hello-contexts}/nodemon.json +0 -0
- /package/templates/{hello-v2 → hello-contexts}/start_postgres_docker.js +0 -0
- /package/templates/{hello-v2 → hello-contexts}/tsconfig.json +0 -0
|
@@ -1,6 +1,86 @@
|
|
|
1
|
-
|
|
2
|
-
import { DBOS } from '@dbos-inc/dbos-sdk';
|
|
1
|
+
// Welcome to DBOS!
|
|
3
2
|
|
|
3
|
+
// This is a sample "Hello" app built with DBOS, Express.js, and Knex.
|
|
4
|
+
// It greets visitors and keeps track of how many times each visitor has been greeted.
|
|
5
|
+
|
|
6
|
+
// First let's import express and DBOS
|
|
7
|
+
import express from "express";
|
|
8
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
9
|
+
|
|
10
|
+
// Then, let's declare a type representing the "dbos_hello" database table
|
|
11
|
+
export interface dbos_hello {
|
|
12
|
+
name: string;
|
|
13
|
+
greet_count: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Now let's define a class with some static functions.
|
|
17
|
+
// DBOS uses TypeScript decorators to automatically make your functions reliable, so they need to be static.
|
|
18
|
+
export class Hello {
|
|
19
|
+
// This function greets a user and increments the greet count in the database.
|
|
20
|
+
// The @DBOS.transaction() decorator ensures that this function runs as a database transaction.
|
|
21
|
+
@DBOS.transaction()
|
|
22
|
+
static async helloTransaction(user: string) {
|
|
23
|
+
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;";
|
|
24
|
+
const { rows } = (await DBOS.knexClient.raw(query, [user])) as { rows: dbos_hello[] };
|
|
25
|
+
const greet_count = rows[0].greet_count;
|
|
26
|
+
const greeting = `Hello, ${user}! You have been greeted ${greet_count} times.`;
|
|
27
|
+
return Hello.makeHTML(greeting);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Finally, we will declare helper functions to serve static HTML to user.s
|
|
31
|
+
|
|
32
|
+
static async readme() {
|
|
33
|
+
const message = Hello.makeHTML(
|
|
34
|
+
`Visit the route <code class="bg-gray-100 px-1 rounded">/greeting/{name}</code> to be greeted!<br>
|
|
35
|
+
For example, visit <code class="bg-gray-100 px-1 rounded"><a href="/greeting/Mike" class="text-blue-600 hover:underline">/greeting/Mike</a></code><br>
|
|
36
|
+
The counter increments with each page visit.`
|
|
37
|
+
);
|
|
38
|
+
return Promise.resolve(message);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// A helper function to create HTML pages with some styling
|
|
42
|
+
static makeHTML(message: string) {
|
|
43
|
+
const page = `
|
|
44
|
+
<!DOCTYPE html>
|
|
45
|
+
<html lang="en">
|
|
46
|
+
<head>
|
|
47
|
+
<title>DBOS Template App</title>
|
|
48
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
49
|
+
</head>
|
|
50
|
+
<body class="font-sans text-gray-800 p-6 max-w-2xl mx-auto">
|
|
51
|
+
<h1 class="text-3xl font-semibold mb-4">Welcome to DBOS!</h1>
|
|
52
|
+
<p class="mt-8 mb-8">` + message + `</p>
|
|
53
|
+
<p class="mb-2">
|
|
54
|
+
To learn how to run this app yourself, visit our
|
|
55
|
+
<a href="https://docs.dbos.dev/quickstart?language=typescript" class="text-blue-600 hover:underline">Quickstart</a>.
|
|
56
|
+
</p><p class="mb-2">
|
|
57
|
+
Then, to learn how to build crashproof apps, continue to our
|
|
58
|
+
<a href="https://docs.dbos.dev/typescript/programming-guide" class="text-blue-600 hover:underline">Programming Guide</a>.<br>
|
|
59
|
+
</p>
|
|
60
|
+
</body>
|
|
61
|
+
</html>`;
|
|
62
|
+
return page;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Now, let's create an Express app and define some routes.
|
|
67
|
+
export const app = express();
|
|
68
|
+
// Parse JSON payloads and make it available to req.body
|
|
69
|
+
app.use(express.json());
|
|
70
|
+
|
|
71
|
+
// We'll serve the README at the root of the app
|
|
72
|
+
app.get("/", async (_, res) => {
|
|
73
|
+
res.send(await Hello.readme());
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Serve this function from HTTP GET requests at the /greeting endpoint with 'user' as a path parameter
|
|
77
|
+
// The handler will in turn call a reliable DBOS operation (helloTransaction) to greet the user
|
|
78
|
+
app.get("/greeting/:user", async (req, res) => {
|
|
79
|
+
const { user } = req.params;
|
|
80
|
+
res.send(await Hello.helloTransaction(user));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Finally, let's start the server
|
|
4
84
|
async function main() {
|
|
5
85
|
await DBOS.launch({expressApp: app});
|
|
6
86
|
|
|
@@ -13,4 +93,7 @@ async function main() {
|
|
|
13
93
|
});
|
|
14
94
|
}
|
|
15
95
|
|
|
16
|
-
|
|
96
|
+
// Only start the server when this file is run directly from Node
|
|
97
|
+
if (require.main === module) {
|
|
98
|
+
main().catch(console.log);
|
|
99
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# DBOS
|
|
1
|
+
# DBOS Background Job
|
|
2
2
|
|
|
3
|
-
This is a [DBOS app](https://docs.dbos.dev/) bootstrapped with `npx @dbos-inc/create`, using [Express.js](https://expressjs.com/) and [Knex](https://docs.dbos.dev/tutorials/using-knex) to interact with postgres.
|
|
3
|
+
This is a [DBOS app](https://docs.dbos.dev/) bootstrapped with `npx @dbos-inc/create`, using [Express.js](https://expressjs.com/) and [Knex](https://docs.dbos.dev/typescript/tutorials/orms/using-knex) to interact with postgres.
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
@@ -40,12 +40,22 @@ npm run start
|
|
|
40
40
|
|
|
41
41
|
To see that it's working, visit this URL in your browser: [`http://localhost:3000/`](http://localhost:3000/).
|
|
42
42
|
|
|
43
|
-
Click on the "
|
|
43
|
+
Click on the "Start Background Job" button.
|
|
44
44
|
|
|
45
|
-
You should
|
|
46
|
-
|
|
45
|
+
You should this message: `Your background task has completed step 0 of 9.`
|
|
46
|
+
As the background job completes steps, the step counter should go up by one!
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Click on "Crash the application" button.
|
|
49
|
+
|
|
50
|
+
The step counter stops increasing.
|
|
51
|
+
On the command line, you will see that the application has stopped.
|
|
52
|
+
Start the application again.
|
|
53
|
+
```bash
|
|
54
|
+
npm run start
|
|
55
|
+
```
|
|
56
|
+
In the browser, you will see that the execution of steps resumes where it left off and eventually completes.
|
|
57
|
+
|
|
58
|
+
Congratulations! You just run a DBOS application.
|
|
49
59
|
|
|
50
60
|
## The application
|
|
51
61
|
|
|
@@ -57,9 +67,9 @@ if (process.env.NEXT_PHASE !== "phase-production-build") {
|
|
|
57
67
|
await DBOS.launch();
|
|
58
68
|
}
|
|
59
69
|
```
|
|
60
|
-
- The workflow is called by the
|
|
70
|
+
- The workflow for the background job is called by the called the GET method in app/tasks/route.ts.
|
|
61
71
|
|
|
62
|
-
- The
|
|
72
|
+
- The GET is called by the component in src/components/BackGroundTask.tsx. It calls the route /tasks.
|
|
63
73
|
|
|
64
74
|
- The component is called from the main UI page.tsx.
|
|
65
75
|
|
|
@@ -72,7 +82,7 @@ To add more functionality to this application, modify `src/operations.ts`. If yo
|
|
|
72
82
|
|
|
73
83
|
## Running in DBOS Cloud
|
|
74
84
|
|
|
75
|
-
To deploy this app to DBOS Cloud, first install the DBOS Cloud CLI
|
|
85
|
+
To deploy this app to DBOS Cloud, first install the DBOS Cloud CLI (example with [npm](https://www.npmjs.com/)):
|
|
76
86
|
|
|
77
87
|
```shell
|
|
78
88
|
npm i -g @dbos-inc/dbos-cloud
|
|
@@ -86,6 +96,5 @@ dbos-cloud app deploy
|
|
|
86
96
|
|
|
87
97
|
## Next Steps
|
|
88
98
|
|
|
89
|
-
- For a detailed tutorial, check out our [programming quickstart](https://docs.dbos.dev/
|
|
90
|
-
- To learn more about DBOS, take a look at [our documentation](https://docs.dbos.dev/) or our [source code](https://github.com/dbos-inc
|
|
91
|
-
|
|
99
|
+
- For a detailed tutorial, check out our [programming quickstart](https://docs.dbos.dev/typescript/programming-guide).
|
|
100
|
+
- To learn more about DBOS, take a look at [our documentation](https://docs.dbos.dev/) or our [source code](https://github.com/dbos-inc).
|
|
@@ -20,6 +20,25 @@ class dbosWorkflowClass {
|
|
|
20
20
|
const greeting = `Hello! You have been greeted ${greet_count} times.`;
|
|
21
21
|
return greeting;
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
@DBOS.transaction()
|
|
25
|
+
static async backgroundTaskStep(i : number) {
|
|
26
|
+
DBOS.logger.info(`Completed step ${i}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@DBOS.workflow()
|
|
30
|
+
static async backgroundTask(i: number) {
|
|
31
|
+
DBOS.logger.info("Hello from background task!");
|
|
32
|
+
for (let j = 1; j <= i; j++) {
|
|
33
|
+
await dbosWorkflowClass.backgroundTaskStep(j);
|
|
34
|
+
DBOS.logger.info("Sleeping for 2 seconds");
|
|
35
|
+
await DBOS.sleepSeconds(2);
|
|
36
|
+
await DBOS.setEvent("steps_event", j)
|
|
37
|
+
}
|
|
38
|
+
DBOS.logger.info("Background task complete!");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
23
42
|
}
|
|
24
43
|
|
|
25
44
|
// Launch the DBOS runtime
|
|
@@ -34,4 +53,9 @@ if (process.env.NEXT_PHASE !== "phase-production-build") {
|
|
|
34
53
|
export async function dbosWorkflow(userName: string) {
|
|
35
54
|
DBOS.logger.info("Hello from DBOS!");
|
|
36
55
|
return await dbosWorkflowClass.helloDBOS(userName);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function dbosBackgroundTask(workflowID: string) {
|
|
59
|
+
DBOS.logger.info("Hello from DBOS!");
|
|
60
|
+
return DBOS.startWorkflow(dbosWorkflowClass, {workflowID: workflowID}).backgroundTask(10);
|
|
37
61
|
}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import Image from "next/image";
|
|
2
|
-
import
|
|
2
|
+
import BackGroundTask from "@/components/client/BackGroundTask";
|
|
3
3
|
|
|
4
4
|
export default function Home() {
|
|
5
5
|
return (
|
|
6
6
|
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
|
7
7
|
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<h1 className="text-xl font-semibold mb-4">Welcome to DBOS!</h1>
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<p className="mb-4">
|
|
14
|
+
DBOS helps you build applications that are <strong>resilient to any failure</strong>—no matter how many times you crash this app, your background task will always recover from its last completed step in about ten seconds.
|
|
15
|
+
</p>
|
|
8
16
|
<div>
|
|
9
|
-
<
|
|
17
|
+
<BackGroundTask />
|
|
10
18
|
</div>
|
|
11
19
|
</main>
|
|
12
20
|
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
3
|
+
|
|
4
|
+
export async function GET(request: Request, { params }: { params: Promise<{ slug: string }> }) {
|
|
5
|
+
|
|
6
|
+
const taskId = (await params).slug;
|
|
7
|
+
DBOS.logger.info(`Received request to check on taskId: ${taskId}`);
|
|
8
|
+
|
|
9
|
+
let step = await DBOS.getEvent(taskId, "steps_event");
|
|
10
|
+
|
|
11
|
+
DBOS.logger.info(`For taskId: ${taskId} we are done with ${step} steps`);
|
|
12
|
+
|
|
13
|
+
return NextResponse.json({ "stepsCompleted": step});
|
|
14
|
+
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
3
|
+
import { dbosBackgroundTask } from "@/actions/dbosWorkflow";
|
|
4
|
+
|
|
5
|
+
export async function GET(request: Request, { params }: { params: Promise<{ slug: string }> }) {
|
|
6
|
+
|
|
7
|
+
const taskId = (await params).slug;
|
|
8
|
+
|
|
9
|
+
DBOS.logger.info(`Received request to start background task taskId: ${taskId}`);
|
|
10
|
+
|
|
11
|
+
DBOS.logger.info(`Started background task taskId: ${taskId}`);
|
|
12
|
+
|
|
13
|
+
await dbosBackgroundTask(taskId)
|
|
14
|
+
|
|
15
|
+
return NextResponse.json({ message: "Background task started" });
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import { useRouter, useSearchParams } from "next/navigation";
|
|
5
|
+
import { dbosBackgroundTask } from "@/actions/dbosWorkflow";
|
|
6
|
+
import { Suspense } from 'react'
|
|
7
|
+
|
|
8
|
+
let intervalInitialized = false;
|
|
9
|
+
|
|
10
|
+
function generateRandomString(): string {
|
|
11
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
12
|
+
const array = new Uint8Array(6);
|
|
13
|
+
crypto.getRandomValues(array); // Fills the array with cryptographically random values
|
|
14
|
+
|
|
15
|
+
return Array.from(array)
|
|
16
|
+
.map(x => chars[x % chars.length])
|
|
17
|
+
.join('');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function BackGroundTask() {
|
|
21
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
22
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
23
|
+
const [taskId, setTaskid] = useState("");
|
|
24
|
+
const [isReconnecting, setIsReconnecting] = useState(false);
|
|
25
|
+
|
|
26
|
+
const router = useRouter();
|
|
27
|
+
const searchParams = useSearchParams();
|
|
28
|
+
|
|
29
|
+
const startBackgroundJob = async () => {
|
|
30
|
+
setIsRunning(true);
|
|
31
|
+
|
|
32
|
+
setCurrentStep(0);
|
|
33
|
+
|
|
34
|
+
let task = taskId
|
|
35
|
+
if (taskId === "") {
|
|
36
|
+
task = generateRandomString();
|
|
37
|
+
setTaskid(task);
|
|
38
|
+
updateQueryParam("id", task);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// start the background job
|
|
42
|
+
try {
|
|
43
|
+
await fetch(`/tasks/${task}`, { method: "GET" });
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("Failed to start job", error);
|
|
46
|
+
setIsRunning(false);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const crashApp = async () => {
|
|
51
|
+
|
|
52
|
+
if(!isRunning) {
|
|
53
|
+
console.log("Not running, nothing to crash");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setIsRunning(false);
|
|
58
|
+
|
|
59
|
+
console.log("Crashing the application");
|
|
60
|
+
|
|
61
|
+
// stop the background job
|
|
62
|
+
try {
|
|
63
|
+
await fetch("/crash", { method: "GET" });
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("Failed to start job", error);
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Update the URL query parameter
|
|
72
|
+
const updateQueryParam = (key: string, value: string) => {
|
|
73
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
74
|
+
params.set(key, value);
|
|
75
|
+
const newUrl = `${window.location.pathname}?${params.toString()}`;
|
|
76
|
+
router.replace(newUrl);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Remove the `id` query parameter from the URL
|
|
80
|
+
const clearQueryParam = (key: string) => {
|
|
81
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
82
|
+
params.delete(key);
|
|
83
|
+
const newUrl = `${window.location.pathname}?${params.toString()}`;
|
|
84
|
+
router.replace(newUrl);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// fetch the current progress
|
|
88
|
+
const fetchProgress = async () => {
|
|
89
|
+
try {
|
|
90
|
+
|
|
91
|
+
if (taskId === "") {
|
|
92
|
+
console.log("No task to monitor");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const response = await fetch(`/step/${taskId}`, { method: "GET" });
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
console.error("Failed to fetch job progress", response.statusText);
|
|
99
|
+
setIsReconnecting(true);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
setIsReconnecting(false);
|
|
103
|
+
|
|
104
|
+
const data = await response.json();
|
|
105
|
+
|
|
106
|
+
console.log("Step completed", data.stepsCompleted);
|
|
107
|
+
|
|
108
|
+
if (data.stepsCompleted) {
|
|
109
|
+
setIsRunning(true);
|
|
110
|
+
setCurrentStep(data.stepsCompleted);
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if (data.stepsCompleted === 10) {
|
|
114
|
+
clearQueryParam("id");
|
|
115
|
+
setIsRunning(false);
|
|
116
|
+
setTaskid("");
|
|
117
|
+
setCurrentStep(0);
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error("Failed to fetch job progress", error);
|
|
123
|
+
setIsRunning(false);
|
|
124
|
+
setTaskid("");
|
|
125
|
+
setIsReconnecting(true);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Polling the progress every 2 seconds while the job is running
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
const idFromUrl = searchParams.get("id");
|
|
132
|
+
if (idFromUrl) {
|
|
133
|
+
setTaskid(idFromUrl);
|
|
134
|
+
setIsRunning(true); // Assume the job is already running if there's an ID
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!intervalInitialized) {
|
|
138
|
+
const interval = setInterval(fetchProgress, 2000);
|
|
139
|
+
intervalInitialized = true;
|
|
140
|
+
return () => {
|
|
141
|
+
clearInterval(interval);
|
|
142
|
+
intervalInitialized = false;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}, [searchParams]);
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<div>
|
|
150
|
+
<div className="flex flex-row gap-2">
|
|
151
|
+
<button onClick={startBackgroundJob} disabled={isRunning} className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
|
|
152
|
+
{isRunning ? "Job in Progress..." : "Start Background Job"}
|
|
153
|
+
</button>
|
|
154
|
+
<button onClick={crashApp} disabled={!isRunning} className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600">
|
|
155
|
+
{ isRunning ? "Crash the application" : "Not Running"}
|
|
156
|
+
</button>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<p>
|
|
160
|
+
{currentStep < 10
|
|
161
|
+
? `Your background task has completed step ${currentStep} of 10.`
|
|
162
|
+
: "Background task completed successfully!"}
|
|
163
|
+
</p>
|
|
164
|
+
<p>
|
|
165
|
+
{isReconnecting ? "Reconnecting..." : ""}
|
|
166
|
+
</p>
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const WrappedBackgroundJobComponent = () => (
|
|
175
|
+
<Suspense fallback={<p>Loading...</p>}>
|
|
176
|
+
<BackGroundTask />
|
|
177
|
+
</Suspense>
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
export default WrappedBackgroundJobComponent;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DBOS Hello with Prisma
|
|
2
2
|
|
|
3
|
-
This is a [DBOS app](https://docs.dbos.dev/) bootstrapped with `npx @dbos-inc/create` and using [Prisma](https://docs.dbos.dev/tutorials/using-prisma).
|
|
3
|
+
This is a [DBOS app](https://docs.dbos.dev/) bootstrapped with `npx @dbos-inc/create` and using [Prisma](https://docs.dbos.dev/typescript/tutorials/orms/using-prisma).
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
@@ -22,10 +22,10 @@ npm run build
|
|
|
22
22
|
|
|
23
23
|
Then, run a schema migration to create some tables.
|
|
24
24
|
Prisma provides rich support for [schema migrations](https://www.prisma.io/docs/orm/prisma-migrate), including automatic generation of migration files from Prisma schema.
|
|
25
|
-
Fore more information, see [our docs](https://docs.dbos.dev/tutorials/using-prisma).
|
|
25
|
+
Fore more information, see [our docs](https://docs.dbos.dev/typescript/tutorials/orms/using-prisma).
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
npx dbos
|
|
28
|
+
npx dbos migrate
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
If successful, the migration should print `Migration successful!`.
|
|
@@ -33,7 +33,7 @@ If successful, the migration should print `Migration successful!`.
|
|
|
33
33
|
Finally, run the app:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
npx dbos
|
|
36
|
+
npx dbos start
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
To see that it's working, visit this URL in your browser: [`http://localhost:3000/greeting/dbos`](http://localhost:3000/greeting/dbos).
|
|
@@ -44,8 +44,8 @@ Congratulations! You just launched a DBOS application.
|
|
|
44
44
|
|
|
45
45
|
## Next Steps
|
|
46
46
|
|
|
47
|
-
- For more information on using Prisma with DBOS, check out [our docs](https://docs.dbos.dev/tutorials/using-prisma).
|
|
47
|
+
- For more information on using Prisma with DBOS, check out [our docs](https://docs.dbos.dev/typescript/tutorials/orms/using-prisma).
|
|
48
48
|
- To add more functionality to this application, modify `src/operations.ts`, then rebuild and restart it. Alternatively, `npm run dev` uses `nodemon` to automatically rebuild and restart the app when source files change, using instructions specified in `nodemon.json`.
|
|
49
|
-
- For a detailed tutorial, check out our [programming quickstart](https://docs.dbos.dev/
|
|
50
|
-
- To learn how to deploy your application to DBOS Cloud, visit our [cloud quickstart](https://docs.dbos.dev/
|
|
51
|
-
- To learn more about DBOS, take a look at [our documentation](https://docs.dbos.dev/) or our [source code](https://github.com/dbos-inc
|
|
49
|
+
- For a detailed tutorial, check out our [programming quickstart](https://docs.dbos.dev/typescript/programming-guide).
|
|
50
|
+
- To learn how to deploy your application to DBOS Cloud, visit our [cloud quickstart](https://docs.dbos.dev/quickstart/)
|
|
51
|
+
- To learn more about DBOS, take a look at [our documentation](https://docs.dbos.dev/) or our [source code](https://github.com/dbos-inc).
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
2
2
|
import { Hello } from "./operations";
|
|
3
3
|
import request from "supertest";
|
|
4
4
|
|
|
5
5
|
describe("operations-test", () => {
|
|
6
|
-
let testRuntime: TestingRuntime;
|
|
7
|
-
|
|
8
6
|
beforeAll(async () => {
|
|
9
|
-
|
|
7
|
+
await DBOS.launch();
|
|
8
|
+
await DBOS.launchAppHTTPServer();
|
|
10
9
|
});
|
|
11
10
|
|
|
12
11
|
afterAll(async () => {
|
|
13
|
-
await
|
|
12
|
+
await DBOS.shutdown();
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Test the HTTP endpoint.
|
|
18
17
|
*/
|
|
19
18
|
test("test-greet", async () => {
|
|
20
|
-
const res = await request(
|
|
19
|
+
const res = await request(DBOS.getHTTPHandlersCallback()!).get(
|
|
21
20
|
"/greeting/dbos"
|
|
22
21
|
);
|
|
23
22
|
expect(res.statusCode).toBe(200);
|
|
24
23
|
expect(res.text).toMatch("Greeting 1: Hello, dbos!");
|
|
24
|
+
expect (await Hello.helloTransaction('bob')).toMatch("Greeting 2: Hello, bob!");
|
|
25
25
|
});
|
|
26
26
|
});
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
// This is the Quickstart Prisma template app. It greets visitors, counting how many total greetings were made.
|
|
4
4
|
// To learn how to run this app, visit the Prisma tutorial: https://docs.dbos.dev/tutorials/using-prisma
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { DBOS } from '@dbos-inc/dbos-sdk';
|
|
7
7
|
|
|
8
8
|
import { PrismaClient } from "@prisma/client";
|
|
9
9
|
|
|
10
10
|
export class Hello {
|
|
11
11
|
|
|
12
12
|
// Serve this function from HTTP GET requests at the /greeting endpoint with 'name' as a path parameter
|
|
13
|
-
@
|
|
14
|
-
@
|
|
15
|
-
static async helloTransaction(
|
|
13
|
+
@DBOS.getApi('/greeting/:name')
|
|
14
|
+
@DBOS.transaction()
|
|
15
|
+
static async helloTransaction(name: string) {
|
|
16
16
|
const greeting = `Hello, ${name}!`;
|
|
17
|
-
const res = await
|
|
17
|
+
const res = await (DBOS.prismaClient as PrismaClient).dbosHello.create({
|
|
18
18
|
data: {
|
|
19
19
|
greeting: greeting,
|
|
20
20
|
},
|
|
@@ -24,8 +24,8 @@ export class Hello {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Serve a quick readme for the app at the / endpoint
|
|
27
|
-
@
|
|
28
|
-
static async readme(
|
|
27
|
+
@DBOS.getApi('/')
|
|
28
|
+
static async readme() {
|
|
29
29
|
const message = Hello.makeHTML(
|
|
30
30
|
`Visit the route <code class="bg-gray-100 px-1 rounded">/greeting/{name}</code> to be greeted!<br>
|
|
31
31
|
For example, visit <code class="bg-gray-100 px-1 rounded"><a href="/greeting/Mike" class="text-blue-600 hover:underline">/greeting/Mike</a></code><br>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DBOS Hello with TypeORM
|
|
2
2
|
|
|
3
|
-
This is a [DBOS app](https://docs.dbos.dev/) bootstrapped with `npx @dbos-inc/create` and using [TypeORM](https://docs.dbos.dev/tutorials/using-typeorm).
|
|
3
|
+
This is a [DBOS app](https://docs.dbos.dev/) bootstrapped with `npx @dbos-inc/create` and using [TypeORM](https://docs.dbos.dev/typescript/tutorials/orms/using-typeorm).
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
@@ -22,10 +22,10 @@ npm run build
|
|
|
22
22
|
|
|
23
23
|
Then, run a schema migration to create some tables.
|
|
24
24
|
TypeORM provides rich support for [schema migrations](https://typeorm.io/migrations), including automatic generation of migration files from entity files.
|
|
25
|
-
Fore more information, see [our docs](https://docs.dbos.dev/tutorials/using-typeorm).
|
|
25
|
+
Fore more information, see [our docs](https://docs.dbos.dev/typescript/tutorials/orms/using-typeorm).
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
npx dbos
|
|
28
|
+
npx dbos migrate
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
If successful, the migration should print `Migration successful!`.
|
|
@@ -33,7 +33,7 @@ If successful, the migration should print `Migration successful!`.
|
|
|
33
33
|
Finally, run the app:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
npx dbos
|
|
36
|
+
npx dbos start
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
To see that it's working, visit this URL in your browser: [`http://localhost:3000/greeting/dbos`](http://localhost:3000/greeting/dbos).
|
|
@@ -44,8 +44,8 @@ Congratulations! You just launched a DBOS application.
|
|
|
44
44
|
|
|
45
45
|
## Next Steps
|
|
46
46
|
|
|
47
|
-
- For more information on using TypeORM with DBOS, check out [our docs](https://docs.dbos.dev/tutorials/using-typeorm).
|
|
47
|
+
- For more information on using TypeORM with DBOS, check out [our docs](https://docs.dbos.dev/typescript/tutorials/orms/using-typeorm).
|
|
48
48
|
- To add more functionality to this application, modify `src/operations.ts`, then rebuild and restart it. Alternatively, `npm run dev` uses `nodemon` to automatically rebuild and restart the app when source files change, using instructions specified in `nodemon.json`.
|
|
49
|
-
- For a detailed tutorial, check out our [programming quickstart](https://docs.dbos.dev/
|
|
50
|
-
- To learn how to deploy your application to DBOS Cloud, visit our [cloud quickstart](https://docs.dbos.dev/
|
|
51
|
-
- To learn more about DBOS, take a look at [our documentation](https://docs.dbos.dev/) or our [source code](https://github.com/dbos-inc
|
|
49
|
+
- For a detailed tutorial, check out our [programming quickstart](https://docs.dbos.dev/typescript/programming-guide).
|
|
50
|
+
- To learn how to deploy your application to DBOS Cloud, visit our [cloud quickstart](https://docs.dbos.dev/quickstart)
|
|
51
|
+
- To learn more about DBOS, take a look at [our documentation](https://docs.dbos.dev/) or our [source code](https://github.com/dbos-inc).
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
2
2
|
import { Hello } from "./operations";
|
|
3
3
|
import request from "supertest";
|
|
4
4
|
|
|
5
5
|
describe("operations-test", () => {
|
|
6
|
-
let testRuntime: TestingRuntime;
|
|
7
|
-
|
|
8
6
|
beforeAll(async () => {
|
|
9
|
-
|
|
7
|
+
await DBOS.launch();
|
|
8
|
+
await DBOS.launchAppHTTPServer();
|
|
10
9
|
});
|
|
11
10
|
|
|
12
11
|
afterAll(async () => {
|
|
13
|
-
await
|
|
12
|
+
await DBOS.shutdown();
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Test the HTTP endpoint.
|
|
18
17
|
*/
|
|
19
18
|
test("test-greet", async () => {
|
|
20
|
-
const res = await request(
|
|
19
|
+
const res = await request(DBOS.getHTTPHandlersCallback()!).get(
|
|
21
20
|
"/greeting/dbos"
|
|
22
21
|
);
|
|
23
22
|
expect(res.statusCode).toBe(200);
|
|
24
23
|
expect(res.text).toMatch("Greeting 1: Hello, dbos!");
|
|
24
|
+
|
|
25
|
+
expect(await Hello.helloTransaction('bob')).toMatch("Greeting 2: Hello, bob!");
|
|
25
26
|
});
|
|
26
27
|
});
|