Skip to content
emitDocs

Get started

Quickstart

Create a cluster, send your first job, and run it in a worker.

You'll create a free cluster, send a send-welcome-email job to it, and run that job in a worker on your machine. You need Node.js 20.3 or later, Go 1.23 or later, or just curl.

  1. Create a cluster

    Sign in at emit.run and choose New cluster. Give it a name, pick a region and choose the Free plan. It needs no card.

    A cluster is your own emit service, with its own address. Its Overview page shows that address, the endpoint your code connects to.

  2. Create an API token

    Open the cluster's Tokens tab and create a token. Leave Spaces blank and keep the scopes it starts with: create, work and read.

    The secret is shown once. Copy the .env block it offers, which holds both values you need:

    .env
    EMIT_URL=https://<your cluster's endpoint>
    EMIT_TOKEN=emit_...

    Load them into your shell with export $(cat .env), or however your project reads .env files.

  3. Install an SDK

    npm init -y
    npm pkg set type=module   # the examples use top-level await
    npm install @emit.run/sdk
    go mod init welcome
    go get github.com/emit-run/sdk-go
    # Nothing to install: every step below is a plain HTTP request.
  4. Run a worker

    A worker asks emit for jobs by name, runs them, and reports back. Jobs live in a space, a named queue; these examples use one called emails, which is created by its first job, so the worker can start before it exists. Returning a value completes the job. Throwing, or returning an error, fails this attempt, and emit tries it again later.

    // worker.ts
    import { Emit } from "@emit.run/sdk";
    
    const emit = new Emit({
      url: process.env.EMIT_URL!,
      token: process.env.EMIT_TOKEN!,
      space: "emails",
    });
    
    type Welcome = { userId: string; email: string };
    
    const worker = emit.worker<Welcome>({ names: ["send-welcome-email"] }, async (job) => {
      await job.progress(50, "rendering");
      console.log(`sending the welcome email to ${job.payload.email}`);
      return { sent: true };
    });
    
    // Finish the jobs in hand before the process exits.
    process.once("SIGINT", () => worker.stop());
    // main.go
    package main
    
    import (
    	"context"
    	"log"
    	"os"
    	"os/signal"
    
    	emit "github.com/emit-run/sdk-go"
    )
    
    type Welcome struct {
    	UserID string `json:"userId"`
    	Email  string `json:"email"`
    }
    
    func main() {
    	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
    	defer stop()
    
    	c := emit.New(emit.Options{URL: os.Getenv("EMIT_URL"), Token: os.Getenv("EMIT_TOKEN"), Space: "emails"})
    
    	worker := c.Worker(ctx, emit.WorkerOptions{Names: []string{"send-welcome-email"}}, func(ctx context.Context, job *emit.HeldJob) (any, error) {
    		var in Welcome
    		if err := job.Decode(&in); err != nil {
    			return nil, emit.Unrecoverable(err) // a payload we can't read won't get better on a retry
    		}
    		if err := job.Progress(ctx, 50, "rendering"); err != nil {
    			return nil, err
    		}
    		log.Printf("sending the welcome email to %s", in.Email)
    		return map[string]bool{"sent": true}, nil
    	})
    
    	select {
    	case <-ctx.Done(): // Ctrl-C
    	case <-worker.Done(): // the worker stopped on its own, for example a revoked token
    	}
    	if err := worker.Stop(); err != nil {
    		log.Fatal(err)
    	}
    }
    # Ask for one send-welcome-email job, waiting up to 30 seconds for one to arrive.
    curl -s "$EMIT_URL/v1/spaces/emails/jobs:claim" \
      -H "Authorization: Bearer $EMIT_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"names": ["send-welcome-email"], "count": 1, "waitMs": 30000}'
    
    # The answer holds the job's id and attempt. Report the result with both:
    curl -s "$EMIT_URL/v1/spaces/emails/jobs:report" \
      -H "Authorization: Bearer $EMIT_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"id": "<job id>", "attempt": 1, "complete": {"result": {"sent": true}}}'

    Start it and leave it running: npx tsx worker.ts (npx fetches tsx the first time; on Node.js 22.18 or later, node worker.ts works too), or go run ..

  5. Send a job

    From another terminal, create a job and wait for its result (npx tsx send.ts, or go run ./send).

    // send.ts
    import { Emit } from "@emit.run/sdk";
    
    const emit = new Emit({
      url: process.env.EMIT_URL!,
      token: process.env.EMIT_TOKEN!,
      space: "emails",
    });
    
    const { id } = await emit.jobs.create("send-welcome-email", {
      userId: "usr_42",
      email: "ada@example.com",
    });
    console.log("created", id);
    
    const result = await emit.jobs.result(id); // follows the job until it ends
    console.log("result", result); // { sent: true }
    // send/main.go
    package main
    
    import (
    	"context"
    	"log"
    	"os"
    
    	emit "github.com/emit-run/sdk-go"
    )
    
    func main() {
    	ctx := context.Background()
    	c := emit.New(emit.Options{URL: os.Getenv("EMIT_URL"), Token: os.Getenv("EMIT_TOKEN"), Space: "emails"})
    
    	created, err := c.Jobs.Create(ctx, emit.NewJob{
    		Name:    "send-welcome-email",
    		Payload: map[string]string{"userId": "usr_42", "email": "ada@example.com"},
    	})
    	if err != nil {
    		log.Fatal(err)
    	}
    	log.Printf("created %s", created.ID)
    
    	var result struct {
    		Sent bool `json:"sent"`
    	}
    	if err := c.Jobs.Result(ctx, created.ID, &result); err != nil { // follows the job until it ends
    		log.Fatal(err)
    	}
    	log.Printf("sent: %v", result.Sent)
    }
    curl -s "$EMIT_URL/v1/spaces/emails/jobs" \
      -H "Authorization: Bearer $EMIT_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name": "send-welcome-email", "payload": {"userId": "usr_42", "email": "ada@example.com"}}'
    # {"created":[{"id":"01M3QSGN0103P7EGVBX9D5NTSN","outcome":"NEW","attempt":0,...}]}
    
    # Read it back: its status, progress and result.
    curl -s "$EMIT_URL/v1/spaces/emails/jobs/01M3QSGN0103P7EGVBX9D5NTSN" \
      -H "Authorization: Bearer $EMIT_TOKEN"

    The worker prints the email address, and the sender prints { sent: true }. In the dashboard, open the emails space from the cluster's Spaces tab to see the job with its progress and result.

Next

Jobs

Retries, delays, idempotency keys and callbacks.

Show progress in a browser

Follow a job live from your frontend.

Workflows

Chain steps, sleep and wait for events in one function.

TypeScript SDK

Every option of the client and the worker.