# Workflow.Settle and Background.Settle — let due work run, in a test

> Test-only. Workflow.Settle(row) runs that row's workflow until it has nothing left to do now: due timers, reminders, an expired state or deadline. Background.Settle() does the same for everything due in the app, including schedule occurrences, which belong to no row you could name. Neither moves the clock; TestClock.Advance does.

<!-- id: testing-settle · area: testing · stability: stable · html: https://osysharp.com/reference/testing/settle/ -->

## Summary        {#summary}
In production, work that falls due later — a state's `Expire`, a `Deadline`, a reminder, a schedule's next occurrence —
is run by the platform's dispatcher on its own cadence. A test does not wait for it. **`Workflow.Settle(row)`** runs
that row's workflow until nothing is due *now*; **`Background.Settle()`** does it for the whole app. Move the clock
first with [`TestClock.Advance`](https://osysharp.com/reference/testing/clock-advance/) when the work is due later than now.

## Signature      {#signature}
```osy syntax
Workflow.Settle(<row>);     // that row's run: due timers fire, routes run, until nothing is due now
Background.Settle();        // everything due in the app, including schedule occurrences
```

## Description    {#description}

### When do I need it?   {#when}
Only for work that **waits for a clock**. A row a commit creates has already entered its workflow when
`UnitOfWork.Commit()` returns — an autostarted `enter` needs no settle ([Tracks and Initial (the field a workflow drives)](https://osysharp.com/reference/workflow/tracks/)). What a settle adds is the
sweep: every timer due at the test's current time fires once, its route runs, and the run moves on.

### Which one?   {#which}
| you want | write |
|---|---|
| a named row's timer, reminder, `Expire` or `Deadline` to fire | `Workflow.Settle(row);` |
| a schedule's occurrence — the row it makes does not exist yet | `Background.Settle();` |
| several rows' runs at once | `Background.Settle();` — one sweep, not one settle per row |

`Workflow.Settle` reads only its row's run: it is cheap, and it cannot fire something that belongs to another row.

### What does it not do?   {#not}
- **It does not move the clock.** Work due tomorrow stays due tomorrow; `TestClock.Advance(TimeSpan.FromDays(1))`
  first, then settle.
- **One settle fires a recurring reminder once**, the way a periodic sweep does — settle again to see the next.
- **It is test-only.** App code has no clock to drain; the dispatcher does it.

```osy title="a hold lapses a day after it was placed" run app=testing-settle
using Osysharp.Workflow;

app Holds {
  model "**/*.osy";
  use Osysharp.Workflow;
}

enum HoldState { Held, Lapsed }

entity Hold {
  [MaxLength(80)] string Title;
  HoldState Status;
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

workflow HoldLife {
  Tracks    = Hold.Status;
  Autostart = true;
  Initial   = Held;

  state Held {
    Expire { Within = TimeSpan.FromDays(1); Accrues = false; }
    on Expire { goto Lapsed; }
  }

  terminal success Lapsed { }
}

[Test]
void A_hold_lapses_once_its_day_has_passed() {
  var h = new Hold { Title = "Blue kayak" };
  UnitOfWork.Commit();

  Workflow.Settle(h);                            // nothing is due yet
  Assert.Equal(HoldState.Held, Hold.Single(x => x.Id == h.Id).Status);

  TestClock.Advance(TimeSpan.FromHours(25));
  Workflow.Settle(h);                            // now the Expire is due, and its route runs
  Assert.Equal(HoldState.Lapsed, Hold.Single(x => x.Id == h.Id).Status);
}
```

## See also       {#see-also}
- [TestClock.Advance and TestClock.Set](https://osysharp.com/reference/testing/clock-advance/) — moving the clock a settle reads
- [Remind (milestone reminders)](https://osysharp.com/reference/workflow/remind/) — reminders, asserted on the audit timeline after a settle
- [Tracks and Initial (the field a workflow drives)](https://osysharp.com/reference/workflow/tracks/) — why an autostarted `enter` needs no settle
- [Schedule (recurring work)](https://osysharp.com/reference/scheduling/schedule/) — schedules, settled with `Background.Settle()`
