Files
Nathan Rajlich e1e64e3de3 docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards

Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.

All executable code is unchanged. Modified skills have their metadata
versions bumped.

* docs: extend writing audit to repository Markdown

Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.

* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00

690 lines
20 KiB
TypeScript

import { connect } from 'node:net';
import * as Stream from 'node:stream';
import { setTimeout as sleep } from 'node:timers/promises';
import type { Transport } from '@vercel/queue';
import {
createWorkflowBaseUrl,
createWorkflowHealthEndpoint,
createWorkflowUrl,
} from '@workflow/utils';
import { getWorkflowPort } from '@workflow/utils/get-port';
import {
getQueueTopicPrefix,
MessageId,
parseQueueName,
type Queue,
QueuePayloadSchema,
type QueuePrefix,
resolveQueueNamespace,
type ValidQueueName,
WorkflowInvokePayloadSchema,
} from '@workflow/world';
import { createWorld } from '@workflow/world-local';
import {
Logger,
makeWorkerUtils,
type Runner,
run,
type WorkerUtils,
} from 'graphile-worker';
import type { Pool } from 'pg';
import { monotonicFactory } from 'ulid';
import { z } from 'zod/v4';
import type { PostgresWorldConfig } from './config.js';
import { MessageData } from './message.js';
function createGraphileLogger() {
const isJsonMode = () => process.env.WORKFLOW_JSON_MODE === '1';
const isVerbose = () => Boolean(process.env.DEBUG);
return new Logger(() => (level: string, message: string, meta?: unknown) => {
if (isJsonMode()) return;
if ((level === 'debug' || level === 'info') && !isVerbose()) return;
const pipe = level === 'error' ? process.stderr : process.stdout;
if (meta) {
pipe.write(
`[Graphile Worker] ${message} ${JSON.stringify(meta, null, 2)}\n`
);
} else {
pipe.write(`[Graphile Worker] ${message}\n`);
}
});
}
const graphileLogger = createGraphileLogger();
const COMPLETED_IDEMPOTENCY_CACHE_LIMIT = 10_000;
// Core records MAX_DELIVERIES_EXCEEDED on delivery 49.
const MAX_GRAPHILE_JOB_ATTEMPTS = 49;
const GraphileHelpers = z.object({
abortSignal: z.instanceof(AbortSignal).optional(),
job: z.object({
attempts: z.number().int().positive(),
}),
});
type HttpExecutionResult =
| { type: 'completed' }
| { type: 'reschedule'; timeoutSeconds: number }
| {
type: 'error';
status: number;
text: string;
headers: Record<string, string>;
};
type RunnerStart = { controller: AbortController; promise: Promise<void> };
type LoopbackTarget = { hosts: string[]; port: number };
/**
* The Postgres queue stores messages under one graphile-worker flow task.
*/
export type PostgresQueue = Queue & {
start(): Promise<void>;
close(): Promise<void>;
};
export function createQueue(
config: PostgresWorldConfig,
pool: Pool
): PostgresQueue {
const port = process.env.PORT ? Number(process.env.PORT) : undefined;
const localWorld = createWorld({ dataDir: undefined, port });
// JSON transport that preserves Uint8Array values via a tagged
// envelope ({ __type: 'Uint8Array', data: '<base64>' }). Required
// for the resilient start path where runInput.input (a Uint8Array)
// is sent through the queue.
const transport: Transport<unknown> = {
contentType: 'application/json',
serialize(value: unknown): Buffer {
return Buffer.from(
JSON.stringify(value, (_key, v) =>
v instanceof Uint8Array
? { __type: 'Uint8Array', data: Buffer.from(v).toString('base64') }
: v
)
);
},
async deserialize(stream: ReadableStream<Uint8Array>): Promise<unknown> {
const chunks: Uint8Array[] = [];
const reader = stream.getReader();
for (;;) {
const { done, value } = await reader.read();
if (done) break;
if (value) chunks.push(value);
}
return JSON.parse(Buffer.concat(chunks).toString(), (_key, v) =>
v !== null &&
typeof v === 'object' &&
v.__type === 'Uint8Array' &&
typeof v.data === 'string'
? new Uint8Array(Buffer.from(v.data, 'base64'))
: v
);
},
};
const generateMessageId = monotonicFactory();
function getJobQueueName(): string {
const jobPrefix = config.jobPrefix || 'workflow_';
return `${jobPrefix}flows`;
}
const createQueueHandler = localWorld.createQueueHandler;
const getDeploymentId: Queue['getDeploymentId'] = async () => {
return 'postgres';
};
const completedMessages = new Set<string>();
const inflightMessages = new Map<string, Promise<void>>();
const inflightWorkflowRuns = new Map<
string,
Promise<'completed' | 'rescheduled'>
>();
let workerUtils: WorkerUtils | null = null;
let runner: Runner | null = null;
let runnerStart: RunnerStart | null = null;
let closing = false;
let startPromise: Promise<void> | null = null;
function markMessageCompleted(idempotencyKey: string) {
completedMessages.delete(idempotencyKey);
completedMessages.add(idempotencyKey);
if (completedMessages.size > COMPLETED_IDEMPOTENCY_CACHE_LIMIT) {
const oldestKey = completedMessages.values().next().value;
if (oldestKey) {
completedMessages.delete(oldestKey);
}
}
}
async function addGraphileJob({
queueId,
body,
messageId,
attempt,
idempotencyKey,
headers,
delaySeconds,
jobKey,
}: {
queueId: string;
body: Buffer | Uint8Array;
messageId: MessageId;
attempt: number;
idempotencyKey?: string;
headers?: Record<string, string>;
delaySeconds?: number;
jobKey?: string;
}) {
const utils = workerUtils;
if (!utils) {
throw new Error('Postgres queue worker utils are not initialized');
}
const runAt =
typeof delaySeconds === 'number' && delaySeconds > 0
? new Date(Date.now() + delaySeconds * 1000)
: undefined;
await utils.addJob(
getJobQueueName(),
MessageData.encode({
id: queueId,
data: Buffer.from(body),
attempt,
messageId,
idempotencyKey,
headers,
}),
{
...(jobKey ? { jobKey } : {}),
...(runAt ? { runAt } : {}),
maxAttempts: MAX_GRAPHILE_JOB_ATTEMPTS,
}
);
}
async function getExecutionBaseUrl(): Promise<string | undefined> {
if (process.env.WORKFLOW_LOCAL_BASE_URL) {
return process.env.WORKFLOW_LOCAL_BASE_URL;
}
if (typeof port === 'number') {
return createWorkflowBaseUrl(`http://localhost:${port}`);
}
if (process.env.PORT) {
return createWorkflowBaseUrl(`http://localhost:${process.env.PORT}`);
}
const detectedPort = await getWorkflowPort({
endpoint: createWorkflowHealthEndpoint(),
});
if (typeof detectedPort === 'number') {
return createWorkflowBaseUrl(`http://localhost:${detectedPort}`);
}
return undefined;
}
function getLoopbackHosts(hostname: string): string[] {
if (hostname === 'localhost') {
return ['127.0.0.1', '::1'];
}
if (hostname === '[::1]') {
return ['::1'];
}
return hostname === '127.0.0.1' || hostname === '::1' ? [hostname] : [];
}
function getLoopbackTarget(baseUrl: string | undefined) {
if (!baseUrl) {
return undefined;
}
const url = new URL(baseUrl);
const hosts = getLoopbackHosts(url.hostname);
if (hosts.length === 0) {
return undefined;
}
return {
hosts,
port: Number(url.port || (url.protocol === 'https:' ? 443 : 80)),
};
}
async function canConnectToLoopbackTarget(
target: LoopbackTarget
): Promise<boolean> {
for (const host of target.hosts) {
const reachable = await new Promise<boolean>((resolve) => {
const socket = connect({ host, port: target.port });
socket.unref();
const finish = (isReachable: boolean) => {
socket.destroy();
resolve(isReachable);
};
socket.setTimeout(200, () => finish(false));
socket.once('connect', () => finish(true));
socket.once('error', () => finish(false));
});
if (reachable) {
return true;
}
}
return false;
}
async function startRunnerUnlessAborted(controller: AbortController) {
if (controller.signal.aborted) {
return;
}
await setupListeners();
}
async function waitForLoopbackAndStartRunner(
controller: AbortController,
target: LoopbackTarget
) {
while (
!controller.signal.aborted &&
!(await canConnectToLoopbackTarget(target))
) {
await sleep(50, undefined, {
ref: false,
});
}
await startRunnerUnlessAborted(controller);
}
function deferRunnerStart(
controller: AbortController,
target: LoopbackTarget
) {
const promise = waitForLoopbackAndStartRunner(controller, target)
.catch((err) => {
if (!controller.signal.aborted) {
console.warn(
'[world-postgres] Failed to start Graphile Worker after local workflow executor became reachable:',
err
);
}
})
.finally(() => {
if (runnerStart?.promise === promise) {
runnerStart = null;
}
});
runnerStart = { controller, promise };
}
async function executeMessageOverHttp({
queueName,
messageId,
attempt,
body,
headers: extraHeaders,
abortSignal,
}: {
queueName: ValidQueueName;
messageId: MessageId;
attempt: number;
body: Uint8Array;
headers?: Record<string, string>;
abortSignal?: AbortSignal;
}): Promise<HttpExecutionResult> {
const headers: Record<string, string> = {
...extraHeaders,
'content-type': 'application/json',
'x-vqs-queue-name': queueName,
'x-vqs-message-id': messageId,
'x-vqs-message-attempt': String(attempt),
};
const baseUrl = await getExecutionBaseUrl();
if (!baseUrl) {
throw new Error('Unable to resolve base URL for workflow queue.');
}
const response = await fetch(createWorkflowUrl(baseUrl, { type: 'flow' }), {
method: 'POST',
duplex: 'half',
headers,
body,
signal: abortSignal,
} as any);
const text = await response.text();
if (!response.ok) {
return {
type: 'error',
status: response.status,
text,
headers: Object.fromEntries(response.headers.entries()),
};
}
try {
const timeoutSeconds = Number(JSON.parse(text).timeoutSeconds);
if (Number.isFinite(timeoutSeconds) && timeoutSeconds >= 0) {
return { type: 'reschedule', timeoutSeconds };
}
} catch {}
return { type: 'completed' };
}
async function migratePgBossJobs(utils: WorkerUtils): Promise<void> {
// Scenario A: Drizzle migration already ran, so the staging table exists
const hasStaging = await pool.query(
`SELECT EXISTS (
SELECT 1 FROM information_schema.tables
WHERE table_schema = 'workflow'
AND table_name = '_pgboss_pending_jobs'
) AS exists`
);
if (hasStaging.rows[0]?.exists) {
const jobs = await pool.query(
`SELECT name, data, singleton_key, retry_limit
FROM "workflow"."_pgboss_pending_jobs"`
);
for (const job of jobs.rows) {
await utils.addJob(job.name, job.data as Record<string, unknown>, {
jobKey: job.singleton_key ?? undefined,
maxAttempts: Math.max(
job.retry_limit ?? 0,
MAX_GRAPHILE_JOB_ATTEMPTS
),
});
}
await pool.query(`DROP TABLE "workflow"."_pgboss_pending_jobs"`);
return;
}
// Scenario B: Drizzle migration didn't run, so the pgboss schema still
// exists
const hasPgBoss = await pool.query(
`SELECT EXISTS (
SELECT 1 FROM information_schema.schemata
WHERE schema_name = 'pgboss'
) AS exists`
);
if (hasPgBoss.rows[0]?.exists) {
const jobs = await pool.query(
`SELECT name, data, singleton_key, retry_limit
FROM pgboss.job
WHERE state IN ('created', 'retry')`
);
for (const job of jobs.rows) {
await utils.addJob(job.name, job.data as Record<string, unknown>, {
jobKey: job.singleton_key ?? undefined,
maxAttempts: Math.max(
job.retry_limit ?? 0,
MAX_GRAPHILE_JOB_ATTEMPTS
),
});
}
await pool.query(`DROP SCHEMA pgboss CASCADE`);
}
}
async function startRunnerWhenExecutorIsReady(): Promise<void> {
if (closing || runner || runnerStart) {
return;
}
const controller = new AbortController();
const promise = (async () => {
const target = getLoopbackTarget(await getExecutionBaseUrl());
if (!target) {
await startRunnerUnlessAborted(controller);
return;
}
if (await canConnectToLoopbackTarget(target)) {
await startRunnerUnlessAborted(controller);
return;
}
if (controller.signal.aborted) {
return;
}
deferRunnerStart(controller, target);
})().finally(() => {
if (runnerStart?.promise === promise) {
runnerStart = null;
}
});
runnerStart = { controller, promise };
await promise;
}
async function start(): Promise<void> {
if (closing) {
return;
}
if (!startPromise) {
startPromise = (async () => {
try {
workerUtils = await makeWorkerUtils({
pgPool: pool,
logger: graphileLogger,
});
await workerUtils.migrate();
await migratePgBossJobs(workerUtils);
await startRunnerWhenExecutorIsReady();
} catch (err) {
startPromise = null;
throw err;
}
})();
}
await startPromise;
if (!closing && !runner && !runnerStart) {
await startRunnerWhenExecutorIsReady();
}
}
const queue: Queue['queue'] = async (queue, message, opts) => {
await start();
const { id: queueId } = parseQueueName(queue);
const body = transport.serialize(message) as Buffer;
const messageId = MessageId.parse(`msg_${generateMessageId()}`);
await addGraphileJob({
queueId,
body,
messageId,
attempt: 1,
idempotencyKey: opts?.idempotencyKey,
headers: opts?.headers,
delaySeconds: opts?.delaySeconds,
jobKey: opts?.idempotencyKey ?? messageId,
});
return { messageId };
};
async function deserializeMessageBody(data: Buffer): Promise<unknown> {
const bodyStream = Stream.Readable.toWeb(Stream.Readable.from([data]));
return transport.deserialize(bodyStream as ReadableStream<Uint8Array>);
}
function createTaskHandler(queue: QueuePrefix) {
return async (payload: unknown, helpers: unknown) => {
const messageData = MessageData.parse(payload);
const graphileHelpers = GraphileHelpers.safeParse(helpers);
const attempt = graphileHelpers.success
? graphileHelpers.data.job.attempts
: messageData.attempt;
const queueName = `${queue}${messageData.id}` as ValidQueueName;
const body = await deserializeMessageBody(messageData.data);
QueuePayloadSchema.parse(body);
const workflowInvoke = WorkflowInvokePayloadSchema.safeParse(body);
const workflowRunSerializationKey =
workflowInvoke.success && !workflowInvoke.data.stepId
? `workflow:${workflowInvoke.data.runId}`
: undefined;
const executeTask = async (): Promise<'completed' | 'rescheduled'> => {
const result = await executeMessageOverHttp({
queueName,
messageId: messageData.messageId,
attempt,
body: messageData.data,
headers: messageData.headers,
abortSignal: graphileHelpers.success
? graphileHelpers.data.abortSignal
: undefined,
});
if (result.type === 'completed') {
return 'completed';
}
if (result.type === 'reschedule') {
// Schedule the follow-up job before we return so a crash cannot
// lose the wake-up request.
await addGraphileJob({
queueId: messageData.id,
body: messageData.data,
messageId: messageData.messageId,
attempt: attempt + 1,
idempotencyKey: messageData.idempotencyKey,
headers: messageData.headers,
delaySeconds: result.timeoutSeconds,
jobKey: messageData.idempotencyKey ?? messageData.messageId,
});
return 'rescheduled';
}
throw new Error(
`[postgres world] Queue execution failed (${result.status}): ${result.text}`
);
};
const idempotencyKey = messageData.idempotencyKey;
if (!idempotencyKey) {
if (workflowRunSerializationKey) {
// Preserve step fan-out while preventing two workflow replays from
// mutating the same run's event log at the same time.
const previous = inflightWorkflowRuns.get(
workflowRunSerializationKey
);
const execution = (previous ?? Promise.resolve())
.catch(() => {})
.then(() => executeTask())
.finally(() => {
if (
inflightWorkflowRuns.get(workflowRunSerializationKey) ===
execution
) {
inflightWorkflowRuns.delete(workflowRunSerializationKey);
}
});
inflightWorkflowRuns.set(workflowRunSerializationKey, execution);
await execution;
return;
}
await executeTask();
return;
}
if (completedMessages.has(idempotencyKey)) {
return;
}
const existing = inflightMessages.get(idempotencyKey);
if (existing) {
await existing;
return;
}
const execution = executeTask()
.then((result) => {
if (result === 'completed') {
markMessageCompleted(idempotencyKey);
}
})
.finally(() => {
inflightMessages.delete(idempotencyKey);
});
inflightMessages.set(idempotencyKey, execution);
await execution;
};
}
async function setupListeners() {
const taskList: Record<
string,
(payload: unknown, helpers: unknown) => Promise<void>
> = {};
const namespace = resolveQueueNamespace(config.namespace);
const workflowPrefix = getQueueTopicPrefix('workflow', namespace);
taskList[getJobQueueName()] = createTaskHandler(workflowPrefix);
runner = await run({
pgPool: pool,
// Default of 50 is high enough to avoid worker-pool exhaustion in
// workflows that use parent→child polling patterns (e.g. awaiting a
// child workflow via `childRun.returnValue` inside the parent).
// Every such poll holds a worker slot for the duration of the child
// run. Recursive workflows like `fibonacciWorkflow` fan out rapidly.
// fib(6) produces ~24 concurrent polling steps at peak, and at
// concurrency=10 (the previous default) it would deadlock on the
// default Postgres setup. See packages/core/src/runtime/run.ts and
// docs/content/docs/changelog/eager-processing.mdx for context.
concurrency: config.queueConcurrency || 50,
logger: graphileLogger,
...(config.applicationManagedShutdown === true && {
noHandleSignals: true,
}),
pollInterval: 500, // 500ms = 0.5s (graphile-worker uses LISTEN/NOTIFY when available)
taskList,
});
}
return {
createQueueHandler,
getDeploymentId,
queue,
start,
async close() {
closing = true;
if (runnerStart) {
runnerStart.controller.abort();
await runnerStart.promise;
runnerStart = null;
}
await startPromise?.catch(() => {});
const activeRunner = runner;
if (activeRunner) {
try {
await activeRunner.stop();
} catch (error) {
if (
!(error instanceof Error) ||
error.message !== 'Runner is already stopped'
) {
throw error;
}
}
await activeRunner.promise.catch(() => {});
runner = null;
}
if (workerUtils) {
await workerUtils.release();
workerUtils = null;
}
startPromise = null;
await localWorld.close?.();
},
};
}