Skip to main content

Effect

Enum Effect 

Source
pub enum Effect {
    Send {
        transport: TransportId,
        frame: Bytes,
    },
    Persist {
        corr: Correlation,
        ops: Vec<StorageOp>,
    },
    PersistAtomic {
        corr: Correlation,
        ops: Vec<StorageOp>,
    },
    PersistFire {
        ops: Vec<StorageOp>,
    },
    Http {
        corr: Correlation,
        req: HttpRequest,
    },
    UploadFile {
        corr: Correlation,
        req: FileUploadRequest,
    },
    HttpFire {
        req: HttpRequest,
    },
    Request {
        corr: Correlation,
        kind: &'static str,
        payload: Bytes,
    },
    Emit {
        event: DomainEventBytes,
    },
    ScheduleTimer {
        id: TimerId,
        after_ms: u64,
    },
    CancelTimer {
        id: TimerId,
    },
}
Expand description

模块吐出的 I/O 意图声明(tagged union,非法组合不可表达)。

执行顺序契约(EFFECT-5):同一个 step 产出的 Vec<Effect> 之间无兑现顺序保证—— driver 可乱序/并发兑现(如 Persist 入队即返回,Send/Emit inline await)。需要顺序的因果 必须经 Correlation 串联(吐 Request/Persist{corr} → 等 PortReply → 再吐下一步), 不可依赖 Vec 下标顺序。

Variants§

§

Send

发送 WS 帧(driver 调用 FrameSender::send)

Fields

§transport: TransportId
§frame: Bytes
§

Persist

需成功回报的持久化:带 Correlation。 driver 执行后必须产出 Tick::PortReply{corr, outcome}。 典型用途:batch_upsert 消息(写成功才推 cursor)。

Fields

§

PersistAtomic

需成功回报的跨 StorageOp 原子持久化:带 Correlation。

与 Self::Persist 有意分开:Persist 保留既有逐操作 fail-fast 语义,不能被悄悄 升格为事务;只有调用方明确选择本变体时,driver 才必须把全部写操作放进同一原子提交单元。 驱动不具备该能力时必须回 PortReply::Err,绝不能降级成普通 Persist。

ops 仅允许写操作;需要读取结果的业务必须用相关性分成后续 step,避免把读侧语义混入 跨平台事务承诺。

Fields

§

PersistFire

幂等 fire-and-forget 持久化:不带 Correlation,不产出 PortReply。

§约束(强制)

仅用于满足以下全部条件的写操作:

  1. 幂等:重复执行结果相同(如 monotonic_upsert 的 MAX guard 天然幂等)
  2. 丢失可接受:写入失败后,下次操作可从旧状态重新推导正确结果

禁止用于:

  • 首次落库的业务数据(消息、用户数据等)
  • 任何依赖“写入成功“才能继续的操作

典型用途:在 Persist{corr} 的 PortReply Ok 后推进单调水位(如同步 cursor)。

Fields

§

Http

HTTP 请求(必达语义):带 Correlation。 driver 执行后必须产出 Tick::PortReply{corr, outcome=Ok(resp)/Err}。

§背压契约(与 Persist 对称,刀1 翻默认)

driver 对必达 Http 在超载时只能 block-back(队满 .await 把背压传导回 tick_tx,慢而不丢),绝不 drop——因为 PortReply 是 load-bearing:响应数据 / inflight-gate 清除 / cursor 推进都依赖它。 「满即丢本条」降级为显式 opt-in(见 HttpFire),不再是 Http 的全局默认。

§

UploadFile

本地文件上传(必达语义):带 Correlation。 driver 读取 local_path 指向的本地文件并执行真实上传后,必须产出 Tick::PortReply{corr, outcome=Ok(resp)/Err}。

§

HttpFire

幂等 fire-and-forget HTTP(可丢弃·丢失可自愈):不带 Correlation,不产出 PortReply。

与 PersistFire 对称——driver 对 HttpFire 用 DropNewest 溢出策略 (队满丢本条/最新来的 + warn),泵不阻塞。

§约束(强制,与 PersistFire 同口径)

仅用于满足以下全部条件的请求:

  1. 不需要响应体(HTTP 仅触发 / ack,真数据走其它通道如 WS)
  2. 丢失可自愈:丢了由后续 cursor-gate / 重连 / proactive resync 重发补偿
  3. 无 inflight 闸依赖其 PortReply 清除

禁止用于:

  • posts/create(发消息必达)
  • 任何 PortReply 推进状态机的请求(sync/notify、increment 等——它们的 PortReply 承载数据 / 清闸 / 推 cursor,丢了会自锁;这类必须用 Http)

当前 helix-im 无真 fire-and-forget HTTP(全部必达),HttpFire 暂为空桶, 为未来正确的请求类(如 telemetry ping / presence 心跳 HTTP)预留正确归属, 并让「Http 默认必达 Block」在类型层成立(opt-in 才放松)。

Fields

§

Request

主动请求宿主(EventBus REP 模式·方向① core→host→core):带 Correlation。

与 Http/Persist 同构——driver 把请求转交宿主(UI / FFI host / JS), 宿主处理后必须产出 Tick::PortReply{corr, outcome}, 经 ExecutionShell::corr_map 定向回投给发起该 corr 的模块。

  • kind:编译期常量路由键(如 “ask_user” / “host_config”),core 不解析其含义
  • payload:已序列化的请求字节(由模块 ACL 序列化)
§与 Emit 的区别

Emit 是单向 PUB(fire-and-forget,无回音); Request 是双向 REP 的发起端(要回音,靠 corr 配对,复用 PortReply 回路)。

driver 实现契约(EFFECT-2):driver 必须兑现并回灌 Tick::PortReply{corr};若是 deferred stub(如 native engine_loop 当前只 warn 不回灌),该 corr 会永久滞留 corr_map、 inflight 闸不清——接线缺口在「第二个发起 Request 的模块接入」时暴露(与 Http/Persist 同口径)。

Fields

§kind: &'static str
§payload: Bytes
§

Emit

发布领域事件(同步 push,不等待)。 driver 调用 EventSink::emit,事件字节已在 ACL-1 序列化。

Fields

§

ScheduleTimer

调度定时器:after_ms 毫秒后产出 Tick::Timer{id}。 driver 维护 TimerRegistry;id 由模块分配(建议模块维护 IdSource)。

Fields

§after_ms: u64
§

CancelTimer

取消定时器(幂等,id 不存在时静默忽略)。

Fields

Trait Implementations§

Source§

impl Debug for Effect

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> MaybeSend for T
where T: Send,

Source§

impl<T> MaybeSync for T
where T: Sync,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more