Skip to content
emitDocs

Concepts

Spaces

A space is a named queue of jobs with its own settings, such as retries, timeouts and who may follow its jobs.

A space is a named set of jobs in your cluster, with its own settings. Use one per area of your product, like emails, billing or imports, so each can have its own retry policy, its own limits and its own tokens.

Every job lives in exactly one space, and the space is part of every job's address: /v1/spaces/emails/jobs/{id}. An SDK client works in one space, which you name when you create it.

Creating a space

You don't have to. A space is created by its first job, with the default settings. To choose its settings first, set it up on the cluster's Spaces tab in the dashboard, or configure it through the API before you send any jobs.

A space's name is up to 256 characters, with no /, and can't start with _emit.. Spaces can't be deleted, but an empty space costs nothing.

Settings

A job takes its space's defaults unless it says otherwise when it's created.

Setting Default What it does
Max attempts (defaultMaxAttempts) 4 Tries for each job, counting the first. 1 means no retries. At most 100.
First retry after (defaultBackoffMs) 1 second The wait after the first failure.
Retry growth (defaultBackoff) exponential, ×2, up to an hour, no jitter How the waits after that grow: exponential (by a factor), linear (the first wait times the retry number) or constant. The longest wait is at most an hour. Jitter spreads retries out: full waits anywhere up to the wait, equal from half of it to all of it.
Timeout (defaultTimeoutMs) 5 minutes How long a worker holds a job before its lease runs out, unless the worker renews it. The SDKs renew it for you.
Fail jobs nobody claims after (unclaimedMs) 7 days A job no worker claims within this time fails, with the error not claimed within 7d. 0 turns it off. From a second to a year.
Events kept per job (maxEvents) 1,000 Up to 3,000.
In-flight limit (maxUnfinished) none New jobs wait while the space has this many unfinished; a batch larger than the limit is refused. See When emit is busy.
Claims per minute (claimsPerMinute) none How many jobs workers may take from the space in a minute.
In order (fifo) off Hands jobs out in the order they were created. See FIFO spaces.
Who may follow a job (publicSubscriptions) signed Whether a browser may follow a job without an API token. See Show progress in a browser.
Webhook secret (webhookSecret) none Signs the space's callbacks and wake-ups. Write-only: it's never shown again.
Wake URL (wake) none A URL emit calls when jobs are waiting, for workers that can't hold a connection open. See Wake-ups.

A cluster splits each space's jobs over a few shards so it can use all its machines. The in-flight limit and claims per minute are applied on each shard separately, so the space's total can be a few times the number you set. Use them as a brake on runaway load, not an exact count.

Changes to retries and timeouts apply to jobs created after the change. Everything else applies at once.

Changing settings

In the dashboard, open the space from the cluster's Spaces tab and choose Space settings. Through an SDK or the API, a token with the admin scope sends the whole set of settings. A setting you leave out goes back to its default, except the webhook secret, the retry growth and the unclaimed window, which stay as they are. To change one setting, read the space first and send it back changed:

const { admin } = new Emit({ url: process.env.EMIT_URL!, token: process.env.EMIT_ADMIN_TOKEN!, space: null });

const { name, ...settings } = await admin.spaces.get("emails");
await admin.spaces.configure("emails", { ...settings, defaultMaxAttempts: 8 });
admin := emit.New(emit.Options{URL: os.Getenv("EMIT_URL"), Token: os.Getenv("EMIT_ADMIN_TOKEN")}).Admin

space, err := admin.Spaces.Get(ctx, "emails")
if err != nil {
	return err
}
space.DefaultMaxAttempts = 8
if _, err := admin.Spaces.Configure(ctx, space); err != nil {
	return err
}
curl -s "$EMIT_URL/v1/spaces/emails" -H "Authorization: Bearer $EMIT_ADMIN_TOKEN" \
  | jq '.defaultMaxAttempts = 8' \
  | curl -s -X PUT "$EMIT_URL/v1/spaces/emails" \
  -H "Authorization: Bearer $EMIT_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @-

The Spaces API lists every field.

FIFO spaces

Without FIFO, workers get the oldest jobs first, but not in strict order: a space is spread over your whole cluster so it can use all of it, and jobs created close together may be handed out in a slightly different order.

A FIFO space hands jobs out strictly in the order they were created. A job that's delayed, or waiting to be retried, takes its place in the order when its wait ends. The price is throughput: a FIFO space runs on a single shard, so it can't spread its work over the whole cluster.

FIFO is fixed when the space gets its first job. Turn it on before then, when you set the space up.

Wake-ups

A worker usually holds a connection open and waits for jobs. A serverless function can't. Give the space a wake URL, and emit POSTs to it when jobs are waiting that nobody has been woken for, and again every 30 seconds while they're still unclaimed. The body names the space and how many jobs of each name are waiting:

JSON
{ "event": "work.pending", "space": "emails", "names": { "send-welcome-email": 3 }, "claim": { "count": 3 }, "timestamp": 1790726272531 }

Your function then claims jobs and reports on them like any worker. A wake-up is signed like a callback, with the same Emit-Signature header. You can limit wake-ups to some job names, and set how many jobs one wake-up stands for.

Tokens and spaces

An API token can be limited to some spaces. A token for emails can't read or create jobs in billing. See Authentication.