# Crash and resume

> Kill a run midway on a durable store, rerun it, and watch the finished step replayed instead of repeated.

Source: https://docs.pyrula.io/getting-started/restart/

A two-step workflow kills its own process between the steps; the rerun picks up the same run.

This page uses Python 3.11 to 3.15 and a POSIX shell, in the directory `pyrula init` wrote
`crash_resume.py` into ([quickstart](https://docs.pyrula.io/getting-started/quickstart.md)). Nothing else needs to run:
the run lives in `.pyrula/dev.db`, which outlives the process.

## 1. Optional: report to Cloud

Export the key from **Setup**, or skip this to run locally.

```bash
export PYRULA_CLOUD_API_KEY="<key>"
```

## 2. Run it twice

```bash
python crash_resume.py
python crash_resume.py
```

The first pass runs step one, then kills its own process:

```text
  step one: RAN (this line should appear exactly once, ever)
  killing this process now - run the script again
```

The second pass waits about five seconds for the dead process's lock to lapse, replays step one from the journal and runs step two:

```text
  step two: RAN
result: {'first': 'one', 'second': 'two'}
```

`step one: RAN` appears once across both passes. The first pass writes the run id to
`.crash_resume_run` so the second finds the same run; the file is deleted on completion.

## 3. See it in Cloud

With a key set, both processes report under one run id. In **Runs**, the run `crash_resume`
shows step one recorded once, then the resumed attempt's step two. Cloud draws no marker where
the first process died.

## Optional: run it on Valkey

To use a production-style store, start Valkey and point the script at it before the two runs:

```sh
docker run -d -p 6379:6379 valkey/valkey:9.1.3
export PYRULA_STORE_URL=valkey://localhost:6379
```

Stop it afterwards with `docker stop`. Run Valkey with `maxmemory-policy noeviction`; `pyrula dev --check --store ...` warns otherwise.

## Side effects

A step recorded before the process died is not run again. An external effect is not
exactly-once: if it succeeded at the provider but the process died before the result was
recorded, the step runs again. Give the provider an idempotency key derived from the work.

If something misbehaves, see [Troubleshooting](https://docs.pyrula.io/getting-started/troubleshooting.md).
