# Deprecated run

> **WARNING:** Passing a plain function to `run` was deprecated in 3.0 and will be removed in a future version. It still works today and logs a warning at startup. `run: workflow(...)` is not deprecated.

## What is deprecated

A plain `run` function starts a long-running loop alongside the actor. Only that form is deprecated. Workflows keep using `run: workflow(...)`.

examples/docs/actors-deprecated-run/before.ts:

```ts
import { actor } from "rivetkit";

// An actor that still uses a plain `run` function
const poller = actor({
  createVars: () => ({ lastPrice: 0 }),
  run: async (c) => {
    while (!c.aborted) {
      c.vars.lastPrice = await fetchPrice();
      await new Promise((resolve) => setTimeout(resolve, 5_000));
    }
  },
  actions: {
    price: (c) => c.vars.lastPrice,
  },
});

async function fetchPrice(): Promise<number> {
  return 42;
}
```

## Start a background task in `onWake`

Start the same loop yourself from `onWake`, which runs on every start, and keep a handle to it in `c.vars`:

1. `onWake` starts the loop and stores its promise in `c.vars`.
2. The loop checks `c.aborted` and passes `c.abortSignal` to anything it waits on, so it exits when the actor starts shutting down.
3. `c.keepAwake` wraps only the work that must finish. Between iterations the actor can still sleep, and `onWake` restarts the loop when it wakes.
4. `onSleep` waits for the loop to exit. `c.abortSignal` fires before `onSleep` runs, so the loop is already stopping.

examples/docs/actors-deprecated-run/background-task.ts:

```ts
import { actor } from "rivetkit";

interface PollerVars {
  lastPrice: number;
  // `onWake` stores its loop here so `onSleep` can wait for it.
  task: Promise<void> | null;
}

interface PollerContext {
  vars: PollerVars;
  aborted: boolean;
  abortSignal: AbortSignal;
  keepAwake<T>(promise: Promise<T>): Promise<T>;
  log: { error(fields: Record<string, unknown>): void };
}

async function pollPrices(c: PollerContext): Promise<void> {
  while (!c.aborted) {
    // Keep the actor awake only while a fetch is in flight. Between polls
    // the actor may sleep, and `onWake` restarts the loop.
    c.vars.lastPrice = await c.keepAwake(fetchPrice());
    await delay(5_000, c.abortSignal);
  }
}

const poller = actor({
  createVars: (): PollerVars => ({ lastPrice: 0, task: null }),

  // `onWake` runs on every start, so the loop is restarted after sleep
  onWake: (c) => {
    c.vars.task = pollPrices(c).catch((error) => {
      c.log.error({ msg: "price poller failed", error });
    });
  },

  // `c.abortSignal` fires on shutdown, so the loop exits on its own
  onSleep: async (c) => {
    await c.vars.task;
  },

  actions: {
    price: (c) => c.vars.lastPrice,
  },
});

// Resolve after `ms`, or as soon as the actor starts shutting down
function delay(ms: number, signal: AbortSignal): Promise<void> {
  return new Promise((resolve) => {
    if (signal.aborted) {
      resolve();
      return;
    }

    const finish = () => {
      clearTimeout(timer);
      signal.removeEventListener("abort", finish);
      resolve();
    };
    const timer = setTimeout(finish, ms);
    signal.addEventListener("abort", finish, { once: true });
  });
}

async function fetchPrice(): Promise<number> {
  return 42;
}
```

Wrapping the whole loop in `c.keepAwake` keeps the actor awake until it is destroyed. Only do that for an actor that must never sleep.

For work that must survive a crash or resume where it left off, store progress in [SQLite](/actors/docs/sqlite) or use a workflow. See [Build a durable job queue](/actors/docs/deprecated/queues#build-a-durable-job-queue) for a complete example.
