moonsim

    Deterministic simulation and model testing toolkit for MoonBit.

    moonbit
    simulation
    deterministic
    model-testing
    replay
    Download zip
    Author
    Version
    0.3.1
    License
    Apache-2.0
    Last updated
    2 months ago
    Downloads
    20

    #moonsim

    MoonBit 的通用确定性事件模拟与模型测试框架。

    moonsim 用同一套虚拟时间、固定 seed、可控变异、invariant、稳定 trace digest 和失败重放能力,测试消息、队列、任务编排、定时器、状态机与外部调用。它适合把偶发的延迟、丢失、重复、乱序和失败变成可复制的模型测试,并将修复策略固化为回归用例。

    moonsim 可为消息可靠性模型和任务编排模型生成有序、可校验、可重放的事件证据。模型既可独立运行,也可接收适配器记录的外部行为,让同一套 invariant 同时服务于设计验证、故障复现和 CI 回归。

    #为什么需要 moonsim

    分布式业务里最难复现的错误,往往不是某个函数算错,而是多个正确操作以意外顺序组合:确认包延迟导致重复投递、超时与成功同时发生、任务依赖尚未完成却被调度,或终态在重试后发生回退。真实时间测试通常运行慢且容易抖动;普通 mock 能替换依赖,却很难系统表达时间、因果关系和故障组合。

    moonsim 的特殊价值是把这些条件压缩成一个可保存、可比较的确定性实验:

    • 虚拟时间:无需等待真实秒数,就能验证 timeout、backoff、截止时间(deadline)和定时任务。
    • 统一事件语言:消息、任务、定时器、状态转移和外部调用共享 tick、因果关系、correlation_id 与 trace。
    • seed 驱动的故障空间:在输入、seed 和变异策略相同时,延迟、丢弃、重复、同 tick 乱序和失败注入的执行结果可以稳定复现,而不是依赖偶发竞态。
    • 失败结果附带证据:每个失败结果都包含 seed、触发的 invariant、事件证据与 digest,可直接 replay,也能固化为修复后的回归用例。
    • 模型与基础设施解耦:同一业务规则可以先在纯模型中快速探索,再由适配器接入记录下来的外部行为;核心不绑定 HTTP、数据库或 MQ 客户端。
    • MoonBit 原生公共 API:模型、示例、测试与报告均可直接参与 MoonBit 项目的 moon check、moon test 和 CI,不需要跨语言测试进程。

    它把“事件何时发生、以什么顺序发生、失败后系统是否仍满足规则”变成可编程、可重复执行的测试对象。

    #与其他语言工具的关系

    moonsim 吸收了多个成熟工具方向中适合软件可靠性测试的能力,并在 MoonBit 中组合成统一闭环:确定性离散事件、故障变异、业务 invariant、稳定摘要、失败重放和 CI 集成。下表用于说明能力定位和设计思想来源,不表示 API 兼容,也不表示完整复刻或替代对应项目。

    工具或方向moonsim 对应提供的能力moonsim 的组合增强
    Akka TestKit消息探测、时序断言和失败路径验证同一事件流还能表达任务、定时器、状态转移与外部调用,并保留跨组件因果关系
    Python SimPy虚拟时间、事件调度和确定性执行面向软件可靠性直接提供 seed 变异、invariant、trace digest 与失败重放,无需自行拼装测试闭环
    Java DESMO-J、CloudSim离散事件排序、调度和容量场景运行以轻量 MoonBit API 聚焦消息、工作流和状态机,可直接进入 moon test 与现有 CI
    Haskell QuickCheck、Python Hypothesis用属性或 invariant 判断大量执行结果失败证据同时保存 seed、策略、关键事件和 digest,可在相同输入、配置和代码版本下确定性 replay
    Jepsen 风格模型验证通过历史事件检查系统规则是否成立在纯模型中快速枚举延迟、丢弃、重复、乱序和失败组合,适合在开发与 CI 阶段高频回归
    手写 mock、fake clock替换依赖、控制时间和构造异常返回把时间、五类事件、因果关系、变异、证据与 replay 做成公共框架,减少重复测试基础设施

    这些能力在其他生态中通常分散于模拟器、属性测试、消息测试工具和故障验证系统;moonsim 的优势是用一套类型化事件 API 把它们连起来。一次失败可以从变异策略进入 invariant,再生成 digest 与事件证据,最后按同一 seed 重放并固化为回归测试。moonsim 为 MoonBit 项目提供了这套开箱可用的组合能力,减少项目重复搭建测试基础设施的成本。

    #安装与最小示例

    下面的步骤从空目录创建独立项目,并使用 mooncakes.io 上的 0.3.1,不依赖本仓库源码:

    moon new moonsim-consumer Set-Location moonsim-consumer moon add zlhahaha/moonsim@0.3.1

    在 cmd/main/moon.pkg 中声明根包依赖:

    import {
    "zlhahaha/moonsim",
    }

    将 cmd/main/main.mbt 替换为以下内容。依赖已经在 moon.pkg 中声明,因此 MoonBit 源文件不需要、也不能再写 import:

    fn main {
    let stream = @moonsim.event_stream()
    let sent = stream.record(
    @moonsim.message_event_kind(), 0, "message.send",
    correlation_id="order-42", source="producer", target="worker",
    )
    ignore(stream.record(
    @moonsim.task_event_kind(), 3, "task.complete",
    correlation_id="order-42", parent_id=sent.id,
    ))

    let policy = @moonsim.event_mutation_policy(
    seed=2026UL, duplicate_percent=100,
    )
    let result = stream.replay(policy)
    let failure = @moonsim.event_failure_case(
    "order_completed_once", stream, policy,
    )
    let replay = failure.replay()
    println("failed_rule=" + failure.rule)
    println("digest=" + result.digest.to_string())
    println("same_seed=" + result.matches_digest(replay).to_string())
    }

    运行:

    moon check --deny-warn moon run cmd/main

    输出中的 digest 是稳定整数;关键结果应为:

    failed_rule=order_completed_once same_seed=true

    这个最小示例演示事件流、变异策略、失败证据和重放接口。业务 invariant 可以根据 EventReplayResult.events 检查最终分类次数、确认前是否丢失、重试上限、依赖顺序与终态保护;完整的 invariant 检查流程见队列与工作流示例。框架同时提供事件结构自身的因果与时间检查。

    #稳定事件类型

    • Message:发送、投递、确认、重试、死信等消息事实。
    • Task:任务就绪、开始、完成、失败、取消与依赖阻塞。
    • Timer:超时、定时触发、退避和 deadline。
    • StateTransition:状态机接受或拒绝的转移。
    • ExternalCall:承载由适配器记录的 HTTP、数据库、MQ 或其他外部交互结果,并与内部事件共同排序和重放。

    Queue、数据库和 MQ 可以通过适配器或上层模型映射到这五类稳定事件,因此新增基础设施不会破坏核心排序、digest 与 replay 语义。

    #能力与证据

    能力可运行证据测试或文档证据
    五类事件、稳定排序与因果关系moon run cmd/mainAPI 文档、core/event_stream_test.mbt
    seed 变异、digest 与失败重放moon run examples/queuecore/event_stream_test.mbt、models/event_stream_test.mbt
    消息重复投递、确认、重试与死信moon run examples/queuemodels/event_stream_test.mbt
    任务依赖、取消与终态保护moon run examples/workflowmodels/event_stream_test.mbt
    HTTP 记录重放兼容适配moon run examples/service_resiliencemodels/event_stream_test.mbt、教程
    10k smoke 与 1k/10k/100k 容量观测moon run cmd/benchmarkcore/event_stream_test.mbt

    #与 MoonBit 常规测试的关系

    moonsim 不替代 moon test,而是作为测试代码中的模型层运行。普通单元测试适合验证一次函数调用;moonsim 补足跨虚拟时间、跨组件、带因果关系和故障注入的行为验证。模型发现的 seed 可以写回普通测试,让同一故障持续进入 CI。

    典型场景包括消息可靠性、重试与超时、任务依赖、状态机、定时器、限流熔断以及外部调用记录重放。它专注模型测试;真实网络压测和生产基础设施运行由对应工具负责。

    #旗舰场景

    moon run examples/queue moon run examples/workflow moon run cmd/main

    examples/queue 展示生产、投递、确认超时、重试、重复投递故障、失败 seed 重放与修复策略。examples/workflow 展示依赖任务、故障注入、终态 invariant 和同 seed 重放。展示中的 FAIL (expected finding) 表示模型按预期发现业务规则被违反,命令仍正常退出。

    #外部调用适配

    现有 RecordedHttpTransport 和 HTTP reliability API 保持兼容。它展示了如何把请求、响应、延迟和错误记录为 ExternalCall,再与消息、任务和定时器共享确定性排序、故障证据、digest 与 replay。当前仓库提供 HTTP 记录与重放示例;数据库和 MQ 可沿用同一事件模型扩展适配器。

    #包结构与稳定性

    • 根包 zlhahaha/moonsim:常用稳定 facade。
    • core/:虚拟时间、类型化事件流、seed、变异、snapshot、invariant 与 replay。
    • models/:消息、队列、任务、状态机和外部调用模型。
    • reports/:实验、seed matrix、timeline 与文本报告。

    EventKind 的五种内置类型和根包入口属于 0.3.x 公共边界;具体模型字段与进阶包可继续演进。详见 API 文档 与 教程。

    #本地验证

    moon fmt moon check --deny-warn moon build moon info git diff --exit-code moon test --deny-warn moon run cmd/main moon run examples/queue moon run examples/workflow moon run examples/service_resilience moon run cmd/benchmark

    benchmark 保留 1k、10k、100k 事件测量;不同机器的耗时不可直接比较。

    • 许可证:Apache-2.0
    • 兼容策略:0.3.x 保持根包 facade 和既有 examples 可用;API 收敛优先采用兼容新增与迁移说明。

    Backoff

    CircuitBreaker

    CircuitBreakerConfig

    CircuitBreakerResult

    CounterSample

    DemoDescriptor

    Duration

    Virtual simulation duration.

    EventFailureCase

    EventId

    Stable simulation event identifier.

    EventKind

    Built-in event categories for deterministic model traces.

    EventMutationPolicy

    EventRecord

    EventReplayResult

    EventStream

    EventStreamSnapshot

    EventView

    ExperimentCase

    ExperimentReport

    FeatureCell

    FeatureCoverage

    FeatureMatrix

    ForkComparison

    HttpFailureCase

    A reproducible failing sample that can be checked after a policy change.

    HttpOutcome

    The externally observed terminal result of an HTTP exchange.

    HttpReliabilityPolicy

    Retry and reliability rules evaluated during a deterministic replay.

    HttpReplayOptions

    Optional deterministic changes applied to a recorded transport.

    HttpReplayResult

    Aggregate result and evidence from a recorded HTTP replay.

    HttpRequest

    The request metadata captured by an external HTTP integration test.

    HttpResponse

    A compact response summary. Bodies are deliberately not retained by default.

    IntRange

    InvariantCheck

    InvariantReport

    LoadBalancerConfig

    LoadBalancerResult

    Message

    MessageBus

    MetricDelta

    MetricDiff

    MetricSnapshot

    Metrics

    ModelSummary

    NetworkConfig

    NetworkResult

    QueueConfig

    QueueResult

    QueueStats

    RecordedHttpExchange

    One HTTP exchange recorded outside the simulator.

    RecordedHttpTransport

    A pure replay transport. It never opens a socket or invokes a real service.

    ReliabilityConfig

    ReliabilityResult

    ReplayBaseline

    ReplayComparison

    RetryConfig

    RetryResult

    Rng

    Deterministic pseudo-random generator for reproducible simulations.

    This generator is not cryptographic. It is intentionally small and portable so simulations behave the same across MoonBit targets.

    RunReport

    RunStep

    RunStopReason

    SampleDistribution

    SampleSummary

    Scenario

    ScenarioCase

    ScenarioExpectation

    ScenarioFailure

    ScenarioReport

    ScenarioSuite

    ScenarioSuiteReport

    ScheduledEvent

    A scheduled simulation event.

    Events are ordered by tick, priority, then id. The id tie-breaker makes same-tick execution stable and replayable.

    SeedMatrix

    SeedMatrixComparison

    ServiceResilienceConfig

    ServiceResilienceResult

    Sim

    Deterministic simulation state.

    SimSnapshot

    StateMachine

    SweepReport

    Tick

    Virtual simulation tick.

    TimelineBucket

    TimelineView

    TimerPlan

    TokenBucket

    TokenBucketResult

    TraceComparison

    TraceEntry

    A deterministic record of an action observed during a simulation run.

    TraceExpectation

    TraceKindCount

    TraceMismatch

    TraceQuery

    TraceQueryResult

    TraceStats

    TrafficConfig

    TrafficResult

    Transition

    TransitionResult

    ValidationIssue

    ValidationReport

    WeightedChoice

    WorkflowPlan

    WorkflowResult

    WorkflowTask

    WorkflowTaskRun

    build_feature_matrix

    build_timeline

    check_counter_at_least

    fn check_counter_at_least(sim :
    Sim
    , name : String, expected : Int) ->
    InvariantCheck

    circuit_breaker_config

    fn circuit_breaker_config(failure_threshold? : Int, reset_timeout? : Int, half_open_successes? : Int) ->
    CircuitBreakerConfig

    compare_forks

    fn compare_forks(left_name : String, left :
    Sim
    , right_name : String, right :
    Sim
    ) ->
    ForkComparison

    default_features

    fn default_features() -> Array[String]

    demo_descriptor

    fn demo_descriptor(name : String, command : String, purpose : String, features : Array[String]) ->
    DemoDescriptor

    demo_names

    fn demo_names() -> Array[String]

    duration

    fn duration(value : Int) ->
    Duration

    event_id

    fn event_id(value : Int) ->
    EventId

    event_mutation_policy

    fn event_mutation_policy(seed? : UInt64, max_delay? : Int, delay_percent? : Int, drop_percent? : Int, duplicate_percent? : Int, reorder_same_tick? : Bool, failure_percent? : Int) ->
    EventMutationPolicy

    event_stream

    Create a generic deterministic event stream.

    expect_trace_contains_detail

    expect_trace_contains_kind

    expect_trace_digest

    expect_trace_kind_count

    fn expect_trace_kind_count(entries : Array[
    TraceEntry
    ], kind : String, expected : Int) ->
    TraceExpectation

    expect_trace_monotonic_ticks

    expect_trace_order

    fn expect_trace_order(entries : Array[
    TraceEntry
    ], before : String, after : String) ->
    TraceExpectation

    experiment_case

    external_call_event_kind

    fn external_call_event_kind() ->
    EventKind

    find_demo

    http_cancelled_outcome

    http_connection_failure_outcome

    fn http_connection_failure_outcome(detail : String) ->
    HttpOutcome

    http_reliability_policy

    fn http_reliability_policy(seed? : UInt64, retry_limit? : Int, timeout_ticks? : Int, backoff_ticks? : Int, deadline_ticks? : Int, rate_limit_per_tick? : Int, circuit_failure_threshold? : Int, circuit_reset_ticks? : Int, accept_late_success? : Bool) ->
    HttpReliabilityPolicy

    http_replay_options

    fn http_replay_options(latency_jitter? : Int, injected_failure_percent? : Int, reverse_same_tick_order? : Bool) ->
    HttpReplayOptions

    http_request

    fn http_request(id : String, http_method? : String, path? : String, attempt? : Int) ->
    HttpRequest

    http_response

    fn http_response(status : Int, body_summary? : String) ->
    HttpResponse

    invariant_check

    fn invariant_check(name : String, passed : Bool, detail? : String) ->
    InvariantCheck

    load_balancer_config

    fn load_balancer_config(seed? : UInt64, jobs? : Int, workers? : Int, max_arrival_gap? : Int, min_service? : Int, max_service? : Int, strategy? : String) ->
    LoadBalancerConfig

    load_balancer_seed_matrix

    fn load_balancer_seed_matrix(seeds : Array[UInt64], strategy? : String) ->
    SeedMatrix

    message_event_kind

    metrics_counter_delta

    fn metrics_counter_delta(left :
    Metrics
    , right :
    Metrics
    , name : String) -> Int

    network_config

    fn network_config(seed? : UInt64, messages? : Int, latency_min? : Int, latency_max? : Int, drop_percent? : Int, retry_delay? : Int) ->
    NetworkConfig

    network_seed_matrix

    fn network_seed_matrix(seeds : Array[UInt64]) ->
    SeedMatrix

    queue_config

    fn queue_config(seed? : UInt64, customers? : Int, max_arrival_gap? : Int, service_time? : Int) ->
    QueueConfig

    recorded_http_exchange

    reliability_config

    fn reliability_config(seed? : UInt64, operations? : Int, fail_percent? : Int, retry_limit? : Int, backoff? : Int) ->
    ReliabilityConfig

    render_demo_catalog

    fn render_demo_catalog() -> String

    render_experiment_report

    fn render_experiment_report(report :
    ExperimentReport
    ) -> String

    render_feature_coverage

    fn render_feature_coverage() -> String

    render_feature_matrix

    fn render_feature_matrix() -> String

    render_metric_diff

    fn render_metric_diff(diff :
    MetricDiff
    ) -> String

    render_metrics_report

    fn render_metrics_report(metrics :
    Metrics
    ) -> String

    render_model_summaries

    fn render_model_summaries(summaries : Array[
    ModelSummary
    ]) -> String

    render_replay_comparison

    fn render_replay_comparison(comparison :
    ReplayComparison
    ) -> String

    render_sample_distribution

    fn render_sample_distribution(metrics :
    Metrics
    , name : String) -> String

    render_scenario_report

    fn render_scenario_report(report :
    ScenarioReport
    ) -> String

    render_scenario_suite_report

    fn render_scenario_suite_report(report :
    ScenarioSuiteReport
    ) -> String

    render_service_resilience_report

    fn render_service_resilience_report(result :
    ServiceResilienceResult
    ) -> String

    render_sim_report

    fn render_sim_report(sim :
    Sim
    , title? : String) -> String

    render_trace_report

    fn render_trace_report(entries : Array[
    TraceEntry
    ], limit? : Int) -> String

    replay_baseline

    retry_config

    fn retry_config(seed? : UInt64, max_attempts? : Int, fail_until? : Int, initial_backoff? : Int, jitter? : Int) ->
    RetryConfig

    retry_seed_matrix

    fn retry_seed_matrix(seeds : Array[UInt64]) ->
    SeedMatrix

    retry_timeout_fault_policy

    retry_timeout_fixed_policy

    retry_timeout_recording

    run_circuit_breaker_model

    fn run_circuit_breaker_model(seed? : UInt64, calls? : Int) ->
    CircuitBreakerResult

    run_token_bucket_model

    fn run_token_bucket_model(seed? : UInt64, requests? : Int) ->
    TokenBucketResult

    service_resilience_config

    fn service_resilience_config(seed? : UInt64, requests? : Int, workers? : Int, queue_limit? : Int, timeout_ticks? : Int, retry_limit? : Int, base_latency? : Int, jitter? : Int, fail_percent? : Int, drop_percent? : Int, rate_limit_capacity? : Int, rate_limit_refill? : Int, rate_limit_interval? : Int, min_success_percent? : Int) ->
    ServiceResilienceConfig

    service_resilience_seed_matrix

    fn service_resilience_seed_matrix(seeds : Array[UInt64]) ->
    SeedMatrix

    state_transition_event_kind

    fn state_transition_event_kind() ->
    EventKind

    sweep_load_balancer_strategies

    fn sweep_load_balancer_strategies(seed? : UInt64, jobs? : Int) ->
    SweepReport

    sweep_point

    sweep_reliability_failure_rates

    fn sweep_reliability_failure_rates(seed? : UInt64) ->
    SweepReport

    task_event_kind

    tick

    fn tick(value : Int) ->
    Tick

    timer_event_kind

    timer_plan

    fn timer_plan(name : String, start_after? : Int, interval? : Int, times? : Int, priority? : Int) ->
    TimerPlan

    trace_digest

    fn trace_digest(entries : Array[
    TraceEntry
    ]) -> UInt64

    trace_entry

    fn trace_entry(tick : Int, event_id : Int, kind : String, detail : String) ->
    TraceEntry

    trace_filter_detail

    trace_filter_kind

    trace_filter_tick_range

    fn trace_filter_tick_range(entries : Array[
    TraceEntry
    ], min_tick : Int, max_tick : Int) -> Array[
    TraceEntry
    ]

    trace_query

    fn trace_query(kind? : String, detail? : String, min_tick? : Int, max_tick? : Int) ->
    TraceQuery

    trace_to_text

    fn trace_to_text(entries : Array[
    TraceEntry
    ]) -> String

    traffic_config

    fn traffic_config(seed? : UInt64, cycles? : Int, cars? : Int, cycle_ticks? : Int) ->
    TrafficConfig

    transition

    fn transition(from : String, event : String, to : String, action? : String) ->
    Transition

    validation_issue

    fn validation_issue(code : String, message : String, severity? : String) ->
    ValidationIssue

    version

    fn version() -> String

    weighted_choice

    fn weighted_choice(label : String, weight : Int) ->
    WeightedChoice

    workflow_critical_path

    fn workflow_critical_path(plan :
    WorkflowPlan
    ) -> Int

    Source Files