---
title: "Timer"
description: "Timer 是一个等到某个时间点的 durable 等待，由 Dex Server 保存。Step 在 WaitFor 中返回它，Timer 触发后运行 Execute。Step 等待期间，没有 Worker 为它占用内存、线程或连接。"
canonical_url: "https://docs.superdurable.io/zh-Hans/concepts/primitives/timer/"
source: "docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/primitives/timer.mdx"
locale: "zh-Hans"
---

# Timer

**Timer** 是一个等到某个时间点的 durable 等待，由 Dex Server 保存。Step 在 **WaitFor** 中返回它，Timer 触发后运行 **Execute**。Step 等待期间，没有 Worker 为它占用内存、线程或连接。

## 什么时候用 Timer

Timer 适合延迟、提醒或截止时间。把它和另一个 condition 组合，就能实现超时。例如，一个 Step 同时等待 [Channel](https://docs.superdurable.io/zh-Hans/concepts/primitives/channel.md) 消息和 Timer，哪个先到就继续。在 **Execute** 中，Step 检查它的 Timer 是否已触发。

## 保证

server 把 Timer 和 Flow 一起保存。Worker 重启和 server failover 都不会丢失它。

## 等待 Timer

这个 Step 等待输入中给出的秒数：

**Python**

```python
class TimerExampleStep(Step[int]):
    def wait_for(self, _context: Context, input: int) -> Wait:
        return Wait.until(Timer.by_duration(timedelta(seconds=input)))

    def execute(self, context: Context, _input: int) -> StepDecision:
        print(context.has_timer_fired())
        return graceful_complete("timer-fired")
```

例子: [examples/python/dex_examples/primitives/timer/timer_flow.py](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/primitives/timer/timer_flow.py)

**Go**

```go
type TimerExampleStep struct {
	dex.StepDefaults
}

func (TimerExampleStep) WaitFor(_ dex.Context, input int) (*dex.Wait, error) {
	return dex.Until(dex.Timer(time.Duration(input) * time.Second)), nil
}

func (TimerExampleStep) Execute(ctx dex.Context, _ int) (*dex.StepDecision, error) {
	fmt.Println(ctx.HasTimerFired())
	return dex.GracefulComplete("timer-fired"), nil
}
```

例子: [examples/go/primitives/timer/workflow.go](https://github.com/superdurable/dex/tree/main/examples/go/primitives/timer/workflow.go)

**Java**

```java
final class TimerExampleStep implements Step<Integer> {
    @Override
    public Class<Integer> getInputType() {
        return Integer.class;
    }

    @Override
    public Wait waitFor(final Context context, final Integer input) {
        return Wait.until(Timer.byDuration(Duration.ofSeconds(input)));
    }

    @Override
    public StepDecision execute(final Context context, final Integer input) {
        System.out.println(context.hasTimerFired());
        return StepDecision.gracefulComplete("timer-fired");
    }
}
```

例子: [examples/java/src/main/java/io/superdurable/dex/primitives/timer/TimerFlow.java](https://github.com/superdurable/dex/tree/main/examples/java/src/main/java/io/superdurable/dex/primitives/timer/TimerFlow.java)

**TypeScript**

```typescript
class TimerExampleStep implements Step<number> {
  public readonly inputCodec = doubleCodec;

  public getStepType(): string {
    return "TimerExampleStep";
  }

  public waitFor(_context: Context, input: number): Wait {
    return Wait.until(Timer.byDuration(input * 1000));
  }

  public execute(context: Context, _input: number): StepDecision {
    console.log(context.hasTimerFired());
    return gracefulComplete("timer-fired");
  }
}
```

例子: [examples/typescript/src/primitives/timer/timer-flow.ts](https://github.com/superdurable/dex/tree/main/examples/typescript/src/primitives/timer/timer-flow.ts)

**Rust**

```rust
#[derive(Default)]
struct TimerExampleStep;

impl Step for TimerExampleStep {
    type Input = i32;

    fn wait_for(&self, _context: &mut Context, input: Self::Input) -> HandlerResult<Wait> {
        Ok(Wait::until(Timer::by_duration(Duration::from_secs(
            input.max(0) as u64,
        ))))
    }

    fn execute(&self, context: &mut Context, _input: Self::Input) -> HandlerResult<StepDecision> {
        println!("{}", context.has_any_timer_fired());
        Ok(StepDecision::graceful_complete("timer-fired".to_string()))
    }
}
```

例子: [examples/rust/src/primitives/timer/flow.rs](https://github.com/superdurable/dex/tree/main/examples/rust/src/primitives/timer/flow.rs)

<a id="如何跳过-timer"></a>

## 跳过 Timer

Client 可以用 **SkipTimer** 跳过一个 Timer。它按 Flow ID、Step execution ID，以及 Timer 的 condition ID 或它在 **WaitFor** 中的 condition 序号选择 Timer。被跳过的 Timer 等同于已经触发。在测试中可以用它；在生产中，也可以用它让等待中的 Step 提前运行。见 [Skip a Timer](https://docs.superdurable.io/zh-Hans/reference/server/runtime-client.md#skip-a-timer)。

在 order-processing 示例的这个测试里，**Ship** Step 等待一个 Timer，测试跳过了它：

**Python**

```python
await client.skip_timer(
    flow_id,
    SHIP_STEP,
    TimerId.by_condition_index(0),
)
```

例子: [examples/python/tests/integ/test_order_processing.py](https://github.com/superdurable/dex/tree/main/examples/python/tests/integ/test_order_processing.py)

**Go**

```go
return integClient.SkipTimer(
	integrationContext(t),
	flowID,
	dex.StepExecutionID{StepType: orderprocessing.ShipStepType},
	dex.TimerID{Index: new(int32)},
) == nil
```

例子: [examples/go/integ/order_processing_test.go](https://github.com/superdurable/dex/tree/main/examples/go/integ/order_processing_test.go)

**Java**

```java
environment.client().skipTimer(
        flowId,
        StepExecutionId.of("Ship"),
        TimerId.byConditionIndex(0));
```

例子: [examples/java/src/test/java/io/superdurable/dex/integ/OrderProcessingIntegTest.java](https://github.com/superdurable/dex/tree/main/examples/java/src/test/java/io/superdurable/dex/integ/OrderProcessingIntegTest.java)

**TypeScript**

```typescript
await environment.client.skipTimer(
  flowId,
  StepExecutionId.of("Ship"),
  TimerId.byConditionIndex(0),
);
```

例子: [examples/typescript/test/integ/order-processing.test.ts](https://github.com/superdurable/dex/tree/main/examples/typescript/test/integ/order-processing.test.ts)

**Rust**

```rust
match environment.client.skip_timer(
    flow_id,
    StepExecutionId::of(&Ship::default()),
    TimerId::by_condition_index(0),
) {
    Ok(()) => return,
    Err(error) => last_error = Some(error),
}
```

例子: [examples/rust/tests/dex_integration.rs](https://github.com/superdurable/dex/tree/main/examples/rust/tests/dex_integration.rs)

Step 如何在 **WaitFor** 中组合 condition，见 [Step](https://docs.superdurable.io/zh-Hans/concepts/step.md)。

## 参考

每个 SDK 参考的 [Timer](https://docs.superdurable.io/zh-Hans/reference/python/timer.md) 页列出该语言的 API 名称。

- [Waits](https://docs.superdurable.io/zh-Hans/reference/python/waits.md) 和
  [Condition results](https://docs.superdurable.io/zh-Hans/reference/python/waits.md#condition-results) 说明 Timer
  如何与其他 condition 组合，以及 Step 如何读取哪个 condition 已经触发。
- [Skip a Timer](https://docs.superdurable.io/zh-Hans/reference/server/runtime-client.md#skip-a-timer) 说明这个 Client 调用。
