Functions
Writing, deploying and operating persistent workers.
View as MarkdownWrite a worker
On the default runtime, export an async default function. In every other runtime, write the long-running process your language would write anyway. Whichever it is, handle errors inside your loop and include a delay, otherwise the worker will consume a full CPU doing nothing useful.
export default async function main() {
while (true) {
try {
console.log('Worker heartbeat', new Date().toISOString());
} catch (error) {
console.error(error);
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
}Deploy
A worker is not bound to JavaScript. With the default runtime the CLI bundles local imports with esbuild from a single entry file; with Python, Go, .NET, Rust, Java, Bun, Deno or Docker it packages the directory and builds it on the server, exactly as it does for an application. Secrets are passed as environment variables either way.
veltic functions deploy PROJECT_ID heartbeat ./worker.ts --memory 256
veltic functions deploy PROJECT_ID importer ./ --runtime go --memory 512Process jobs reliably
Store job state in PostgreSQL. Processes restart, so handlers must be idempotent. Use an atomic claim so competing workers never take the same row.
update jobs
set status = 'running', claimed_at = now()
where id = (
select id from jobs
where status = 'pending'
order by created_at
for update skip locked
limit 1
)
returning *;When a worker dies
Exceeding the hard memory limit terminates the container through the kernel; the restart policy retries up to five times. Check the logs and the memory chart in the dashboard rather than assuming a transient fault.