Skip to content

Commit f925b44

Browse files
authored
docs: Document service readiness probes (#13472)
## Summary - Add a guide for starting a task after a long-running service becomes ready - Combine `with`, `dependsOn`, and a finite health probe without adding new Turborepo primitives - Link the guide from the Guides navigation and overview Closes #1497. ## Testing - `pnpm --filter docs lint` - `pnpm --filter docs check-links` - `pnpm --filter docs check-types`
1 parent 4778467 commit f925b44

3 files changed

Lines changed: 152 additions & 0 deletions

File tree

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
title: Coordinating development runtime dependencies
3+
description: Learn how to coordinate development services that depend on each other at runtime.
4+
product: turborepo
5+
type: guide
6+
summary: Combine a readiness probe with with and dependsOn to coordinate runtime dependencies between development services.
7+
prerequisites:
8+
- /docs/crafting-your-repository/developing-applications
9+
related:
10+
- /docs/reference/configuration
11+
- /docs/reference/run
12+
---
13+
14+
Some development tasks need another service to be available before they can start. For example, a frontend may need an API to be accepting requests before its development server starts.
15+
16+
<Callout type="info">
17+
This pattern is intended for coordinating services during local development. For CI and production, use the service orchestration and readiness capabilities provided by your CI provider or deployment platform.
18+
</Callout>
19+
20+
Turborepo can coordinate this workflow by combining:
21+
22+
- [`with`](/docs/reference/configuration#with) to start the service alongside the task that needs it
23+
- [`dependsOn`](/docs/reference/configuration#dependson) to wait for a finite readiness probe to succeed
24+
- [`persistent`](/docs/reference/configuration#persistent) to mark the service as long-running
25+
26+
This guide configures packages named `web` and `api`, where the API's development server exposes a health endpoint at `http://localhost:3001/health`.
27+
28+
## Create a readiness probe
29+
30+
The readiness probe should retry until the service is available, exit successfully when it is ready, and fail after a timeout. Keep the readiness condition specific to your service so it can check everything the dependent task requires, such as a database connection or completed initialization.
31+
32+
```js title="./apps/api/scripts/wait-for-ready.mjs"
33+
const healthUrl = "http://localhost:3001/health";
34+
const deadline = Date.now() + 60_000;
35+
36+
while (Date.now() < deadline) {
37+
try {
38+
const response = await fetch(healthUrl, {
39+
signal: AbortSignal.timeout(1_000),
40+
});
41+
42+
if (response.ok) {
43+
console.log(`API is ready at ${healthUrl}`);
44+
process.exit(0);
45+
}
46+
} catch {
47+
// The service may still be starting. Try again until the deadline.
48+
}
49+
50+
await new Promise((resolve) => setTimeout(resolve, 500));
51+
}
52+
53+
console.error(`API did not become ready at ${healthUrl} within 60 seconds`);
54+
process.exit(1);
55+
```
56+
57+
Add scripts for the long-running service and its finite readiness probe:
58+
59+
```json title="./apps/api/package.json"
60+
{
61+
"name": "api",
62+
"scripts": {
63+
"dev": "node ./server.mjs",
64+
"dev:ready": "node ./scripts/wait-for-ready.mjs"
65+
}
66+
}
67+
```
68+
69+
The `api#dev:ready` script does not start the API. It only reports whether the API started by `api#dev` is ready.
70+
71+
The `web` application also needs a `dev` script:
72+
73+
```json title="./apps/web/package.json"
74+
{
75+
"name": "web",
76+
"scripts": {
77+
"dev": "start-web"
78+
}
79+
}
80+
```
81+
82+
## Register the tasks
83+
84+
Register both task names in the root `turbo.json`. The readiness probe must not be cached because its result depends on the state of a running service rather than files in the repository.
85+
86+
```json title="./turbo.json"
87+
{
88+
"$schema": "https://turborepo.dev/schema.json",
89+
"tasks": {
90+
"dev": {
91+
"cache": false,
92+
"persistent": true
93+
},
94+
"dev:ready": {
95+
"cache": false
96+
}
97+
}
98+
}
99+
```
100+
101+
Next, use a [Package Configuration](/docs/reference/package-configurations) to describe the `web` application's runtime requirements:
102+
103+
```json title="./apps/web/turbo.json"
104+
{
105+
"extends": ["//"],
106+
"tasks": {
107+
"dev": {
108+
"with": ["api#dev"],
109+
"dependsOn": ["api#dev:ready"]
110+
}
111+
}
112+
}
113+
```
114+
115+
When `web#dev` is selected, Turborepo:
116+
117+
1. Adds the persistent `api#dev` task to the run because of `with`.
118+
2. Starts `api#dev` and the non-persistent `api#dev:ready` probe.
119+
3. Starts `web#dev` after the probe exits successfully.
120+
4. Continues monitoring `api#dev` and `web#dev` until you stop Turborepo or either task exits.
121+
122+
Do not add `api#dev` to `dependsOn`. A persistent task does not exit, so it cannot complete and unblock a dependent task. The finite `api#dev:ready` probe provides that completion signal instead.
123+
124+
## Run the application
125+
126+
Select the `web` application to start the complete workflow:
127+
128+
```bash title="Terminal"
129+
turbo run dev --filter=web
130+
```
131+
132+
The default concurrency has enough capacity for this workflow. If you set [`--concurrency`](/docs/reference/run#--concurrency-number--percentage), use at least `3` so Turborepo has a slot for each persistent task and another for the readiness probe.
133+
134+
If the API does not become ready before the probe's timeout, the probe exits with an error and `web#dev` does not start. Turborepo stops all tasks when you interrupt the run.
135+
136+
## Probe other readiness conditions
137+
138+
An HTTP endpoint is only one way to determine readiness. The probe script can wait for any condition your service exposes, including:
139+
140+
- A TCP port accepting connections
141+
- A file or Unix socket being created
142+
- A database accepting queries
143+
- A specific initialization check succeeding
144+
145+
You can implement the probe yourself, as shown above, or use a utility such as [`wait-on`](https://www.npmjs.com/package/wait-on). In either case, ensure the probe retries transient failures, has a timeout, and exits with a non-zero status when the service does not become ready.

apps/docs/content/docs/guides/index.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ In our community-supported guides, you'll find examples of how to use `turbo` wi
4444
href="/docs/guides/single-package-workspaces"
4545
/>
4646

47+
<Card
48+
title="Runtime dependencies"
49+
description="Coordinate services that depend on each other while running"
50+
href="/docs/guides/coordinating-runtime-dependencies"
51+
/>
52+
4753
<Card
4854
title="Generating code"
4955
description="Create new code fast"

apps/docs/content/docs/guides/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"ci-vendors",
66
"tools",
77
"single-package-workspaces",
8+
"coordinating-runtime-dependencies",
89
"generating-code",
910
"skipping-tasks",
1011
"microfrontends",

0 commit comments

Comments
 (0)