# 将原子变成一个遥感网络

*一个微小的原始体 将同时工作变成一个协调的适应系统*

**时空信号模式**

<!--category-- ASP.NET, Architecture, Systems Design, Async -->
<datetime class="hidden">2025-12-12T16:00</datetime>

内 **[部分#1](/blog/fire-and-dont-quite-forget-ephemeral-execution)** 我们建造了短时处决@ - @ leged @ MS K1} 私人 @ MPK2 self @ I-_ 清除同步工作流程@ MCK4 in **[部分#2](/blog/ephemeral-execution-library)** 我们把它变成一个可重复使用的库 与协调员, 关键管道\ , 和DI集成.

此篇文章添加一个小特点, 改变一切@: @ @ **信号信号**.

## NUGET!!!

这现在也出现在大多数卢西德.\ ephearals Nuget 软件包中 [超过 @20 @ mostlucid@ . @epheperals 模式和%'#atoms@'}](https://www.nuget.org/packages?q=mostlylucid.ephemeral&includeComputedFrameworks=true&prerel=true&sortby=created-desc).

[![Nuget 元数](https://img.shields.io/nuget/v/mostlylucid.ephemeral.svg)](https://www.nuget.org/packages/mostlylucid.ephemeral)
[![驾照许可证](https://img.shields.io/badge/license-Unlicense-blue.svg)](../../UNLICENSE)

## 源代码文件

完整源代码在 [基特Hub 库](https://github.com/scottgal/mostlylucid.atoms)

信号基础设施位于 :

|QFile *|Q目的 *|Q*
|------|---------|
| [信号@.%cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Signals.cs) | `SignalEvent`, `SignalRetractedEvent`, `SignalPropagation`, `SignalConstraints`, `SignalSink`, `ISignalEmitter`, `AsyncSignalProcessor` |
| [短期行动=.cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/EphemeralOperation.cs) “|” 操作中的信号发射和撤回
| [时间选择@. @cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/EphemeralOptions.cs) @ | @ 信号@ MS K1 @ reactive 配置 @ *(`CancelOnSignals`, `DeferOnSignals`, `OnSignal`, `OnSignalRetracted`) |
| [字符串父书签@. @cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/StringPatternMatcher.cs) |Glob- 风格模式匹配信号过滤@|
| [信号发送器 @ .% cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/SignalDispatcher.cs) | Async 信号路由, 模式与 @(支持匹配 `*`, `?`-=YTET -伊甸园字幕组=- 翻译:
| [/Signaling HttpClient_.cs 示例](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Examples/SignalingHttpClient.cs) |样板精细-Grained信号发射 HTTP调用@|
| [例如:/Adaptating Transalation Servicice@.cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Examples/AdaptiveTranslationService.cs) “|” 适应率受信号限制 - 以延迟为基础
| [/Signal BircitBreaker}.cs 示例](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Examples/SignalBasedCircuitBreaker.cs) | 巡回断路器读取时空信号窗口 @|
| [例如:/ 遥测信号Handler .cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Examples/TelemetrySignalHandler.cs) |Async信号处理与遥测集成

[TOC]

---


## 问题=:}孤立原子

我们的时长协调员非常擅长处理工作 , 但他们孤立的' MESK2 每个协调员都知道自己的行动

```csharp
// Translation coordinator has no idea that...
await translationCoordinator.EnqueueAsync(request);

// ...the API just hit a rate limit
// ...another service is experiencing backpressure
// ...a downstream dependency is slow
```

我们可以联结明确的依附关系 ,,但这样就产生了连系 **环境意识** 能够感知环境而不直接连结的.协调员

让处决原子留下痕迹的信号 在它们的短暂窗口\ .}这些踪迹表现得像短-}活生生的事实=:}

- *@"#这个API 仅按速率%-}限制="*
- *" @ this user has unfailed {3} 乘以"} 此用户已失败 。*
- *@"A sibling 操作仍在等待 在网关@"#*

然后,协调员可以根据窗口中可见的信号来改变他们的行为。 “.”是指没有依附关系的环境意识?“.”

---


## 操作的解决方案@ : @ 信号

从 [信号@.%cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Signals.cs):

```csharp
public readonly record struct SignalEvent(
    string Signal,
    long OperationId,
    string? Key,
    DateTimeOffset Timestamp,
    SignalPropagation? Propagation = null)
{
    public int Depth => Propagation?.Depth ?? 0;
    public bool WouldCycle(string signal) => Propagation?.Contains(signal) == true;
    public bool Is(string name) => Signal == name;
    public bool StartsWith(string prefix) => Signal.StartsWith(prefix, StringComparison.Ordinal);
}
```

执行操作时可以发出信号@.}这些信号在运行时间窗口旁边的“. ” 当操作老化为 @, 时,信号随其而流逝 *.*

{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}没有留言经纪人吗?

因为信号存在于时空窗口内 它们继承了它的保证 : 绑定大小 MS K2 自动老化 , 和零寿命周期管理@. *

---


# 时间信号法

## Law {1} - 信号从不暗中触发执行

一个信号*,* 本身 *,* 不导致处决 *MS K2*
它只记录在时间窗口中的事实 .
没有运行是因为信号被发出\"."

## 有关明确信号的 ,}本地 MS K3和可选

如果一个协调员定义了 OnSignal handler,, 它会在发送“ -” 信号时同步运行, 但仅仅因为协调者选择附加“ MPK2”
爱慕者不知道或关心... ....
删除所有处理器, 核心行为不变@. @%

## 法律是本地到原子的信号

信号只附在发射它的原子的原子 / 操作上
从来没有信号变异或注解其他原子
没有共享的可编程总线@. @%

## 法律 4 MS K1 信号是附加的}- 只有事实

发送信号时将一个事实附加到原子的原子上@’ @s history_.}
信号从未更新或覆盖@. @%
减量只移除自发的信号@. @%

## 信号表面断裂和时间

仅在协调器中存在信号@’ @sepheral window_.{}
它们自动过期,因为窗口老化了@. @%
没有什么是持久的,除非你明确建立持久性... ....

## Law 6 MS K1 观察者读@, 他们不写

当协调员“ “” 检查密钥 K”, 的信号时, 它会扫描“ MPK2 ” 。

窗口中的原子

以及当地对这些原子的信号
观察家从不修改原子=’}s signal state_.

## 法律@7 @ @ -事件@ MS K2}类似行为是一层_ , 不是一个原始的

如果您想要信号来驱动 Async 工作流程 @ , 您必须使用\ MS K1@

信号发送器

Async 信号处理器

.

这些是建在信号上方的可选层,}不是语义学的一部分 □.

## 法律: 在任何情况下,不得在任何环境下发生突变。

没有原子可以更改快照@ , @ state\ , 信号 @ MS K2 或其它原子元数据@ I.}
校对:Soup

- 信号信号

- 遥感

- 窗口窗口

- 政策、政策和

**不通过写入@. @%**

## 法律 9 MS K1 全球观点是衍生的 MSSK2永不可变

信号ink 或 swarm - 集合的表面可能显示信号 {—} 的综合视图
但它总是在读@- @ only\ ,}从不具有权威性 @,_ 从来就没有可写@MS K3

## 法律=10 - 清除手持者 放弃同样的核心系统

如果所有处理者@(_OnSignal_,}调度员 @,}进程员 @ )}是独立处理的\ ,
系统保持完全正确和可预测
信号仍有意义,因为它们是事实 , 而不是触发器

### 最佳分析@: @ 脚印 @ ,_ 不是指令

**事件活动** 就像一个电话 :

> 收起电话,回应

**信号** 就像雪中的脚印 :

> {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}如果你想知道我去哪里了 {\fnarial black\fs12\bord0\shad1\1cHF0F0F0}

这就是为什么信号永远不会破解吗? , 从不阻塞吗? ,,从不与控制流互动 除非你 *选择* 来调查他们吗?

### 此删除是什么

区别很重要,因为信号消除了

“|”问题“|”事件是否已经“MS K2”信号避免了 |
|---------|:--------------:|:----------------:|
| 串联 *| 出版商 *→ 订户*| 无#|
@|_立即反应要求@|_Ambient_,}民调准备时请回答 |_
@ |_ 反馈回路@ MS K1_ 处理器可以触发操作器 @ I|} 除非明确询问 @ MPK3# 否则没有回路
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}命令语义
@|_提供保障%|}必须交付 /_Handled {|}没有发货 *,* 仅仅存在 <|>
| 错误传播@| 处理器错误传播 @| 孤立的\|
“| ”“再生危险 ” “| 常见”“| ” 不可能“MSC3 ”
@ | 连锁故障 # 一个处理器失败 * @ I,# 链条断裂 * 没有链条打破 *|*

### 快速比较

“|”特写“|”事件“MS K2”信号“|”
|---------|--------|---------|
→ 订户 @) |没有#|
-=YTET -伊甸园字幕组=- 翻译:
@| 发送@| 保证}/ 尝试 *| 没有发货* , 只是存在\|
@|_反应@|}要求{|}可选}#|
| 数据有效载荷 @| 通常重 *| 小字符串元数据@|
|#存储@|_None @|%Sliding LRU#-}风格窗口 @MS K4
@| @ 寿命@ | @ 即时 @ MS K2 @ decays 自动 @ MPK3 @
@|_失败模式@|}许多#|}几乎没有

### 《守则》差异

**事件处理方式 @(_classici=):}@**

```csharp
public event Action RateLimited;

try
{
    await CallApiAsync();
}
catch (RateLimitException)
{
    RateLimited?.Invoke(); // Makes someone else act right now
}
```

问题 @:

- 谁是反应者=?
- 按什么顺序 ?
- 如果两个处理者有冲突呢?
- 如果一个操作员扔了?怎么办
- 万一它误了时间呢?
- 如果来电者不想要这个行为怎么办?

**信号接近@( @epheperal_):#**

```csharp
try
{
    await CallApiAsync(ct);
}
catch (RateLimitException ex)
{
    op.Signal($"rate-limit:{ex.RetryAfterMs}ms");
    throw;
}
```

这里什么也没有发生, . 稍后... ...,...

```csharp
if (translator.HasSignal("rate-limit"))
{
    await Task.Delay(1000);   // Act when *we* choose
}
```

注::

- 不直接连接
- 无惊喜电话
- 没有执行跳跃
- 没有回电地狱的地狱
- 没有横跨@ - @ tread weirds
- 只有当我们 *询问要求* 查看

### @ "_ Aha!"}线条

> **事件传输控制@.信号传输上下文 @.**

{\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}这整个精神模式都写在一句话里 {\fnarial black\fs12\bord1\shad0\4aH3C\1cH80FFFF\b0}

### 真正信号是什么

取决于您的背景@: @%

-=YTET -伊甸园字幕组=- 翻译:
|----------|------------|
| **系统思考者** 用于间接协调的STIMPK1基体
| **工程师** “|” 轻量级元数据附在捆绑滑动窗口中的操作中,“|”
| **PL/ 货币呆子** 暗含的, "时间黑板与捆绑的通货货币语义结合" |
| **框架用户** @ | @ an in-_ process@ MS K2} 自我=-} 清理状态表层, 您可以随时查询\ |}

共享的@, @ 绑定的内存表面留下痕迹@ ._ 任何人都可以查看它们 @ MS K2} 没有人必须响应\ . 这是根本上的一种 *悬浮* 同样的蚂蚁使用相同的黑板系统 在早期AI,}和同一个现代CRDT八卦网络提示

---


## 与其它方法相比如何

### 应用程序透视@ / @ open 遥测

```csharp
using var activity = source.StartActivity("ProcessOrder");
activity?.SetTag("order.id", orderId);
activity?.SetTag("rate.limited", true);
```

**最佳**: 分布在各服务处的追踪@, long- 长期遥测存储 @, 相关IDsMS K4

**使用遥测方法**: 您需要通过多个服务跟踪请求@, 用于分析 @,}或与监控工具整合=.

**使用时空信号**: 您需要在 @ MS K1 process environmental conformation *% , 或don' 想要遥测基础设施@.*

### 反弹扩展名 @ (_Rx})

```csharp
var rateLimits = Observable.FromEventPattern<RateLimitEventArgs>(
    h => api.RateLimitHit += h,
    h => api.RateLimitHit -= h);

rateLimits
    .Throttle(TimeSpan.FromSeconds(1))
    .Subscribe(e => HandleRateLimit(e));
```

**最佳**:复杂事件处理@,时间 @-基于操作},结合多个事件流\.

**使用 Rx 当**您需要复杂的时间查询@ ( @ windowing @ MS K2 @ debouncing @, @ 合并流=).}

**使用时空信号**: 您想要更简单的民调Q-基于感知@, 自动清理 @, 或与操作跟踪整合\.

### 中继R 通知

```csharp
public class RateLimitNotification : INotification
{
    public int RetryAfterMs { get; init; }
}

await _mediator.Publish(new RateLimitNotification { RetryAfterMs = 5000 });
```

**最佳**: dcoupled in @-Q process 事件处理与多个操作器@.

**使用中位tR**: 您想要多个处理器对同一事件同步响应\ .}

**使用时空信号**: 您想要没有明确订阅的環境感知@, self @-清理历史_,或与被捆绑的行刑合并}=.

### Polly 电路断开器

```csharp
var circuitBreaker = Policy
    .Handle<HttpRequestException>()
    .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
```

**最佳**@:Z 个人电话的恢复力与自动州管理

**使用 Polly**: 您需要每-呼叫恢复能力 用自动一半MS K2%open}/ 已关闭的过渡@.#

**使用时空信号**: 您想要在多个操作中提高环境意识 @,自定义电路逻辑@,或与运行跟踪整合\.

**结合他们**“: ” 在您的工作身体里使用 Polly @,}当电路出轨时发出信号@. *

### 比较表

| 解码 NSK5 自定义逻辑 *| 集成*| *
|----------|:-------------:|:---------------:|:---------:|:------------:|:-----------:|
@| @开放的远程技术 @MS K1 @ ❌ @ @ I| @ ❌} @| @ @#✅ @ @ @%|_ @#❌ @ @~|#外部工具 @MSC10 @
|+反应扩展名 @|+ @MS K2# |Q} @✅+#|(✅+) @MSC7+#(✅+#)(|+Complication #|_)
❌ @✅~|#✅_|手册@|#
|+Polly 电路断路器 @|+ @MS K2#@|Q} @❌+#|+#❌_ @ @NSK7+Z❌+|+PER}(-呼叫|)
| **短讯信号** | MS K6 ✅ NSK8 内建

---


## 提升和减缩信号

业务实施 `ISignalEmitter`:

```csharp
public interface ISignalEmitter
{
    // Emit signals
    void Emit(string signal);
    bool EmitCaused(string signal, SignalPropagation? cause);

    // Retract (remove) signals
    bool Retract(string signal);
    int RetractMatching(string pattern);
    bool HasSignal(string signal);

    long OperationId { get; }
    string? Key { get; }
}
```

在你工作的身体里 :

```csharp
await coordinator.ProcessAsync(async (item, op, ct) =>
{
    try
    {
        var result = await CallExternalApiAsync(item, ct);

        if (result.WasCached)
            op.Signal("cache-hit");

        if (result.Duration > TimeSpan.FromSeconds(2))
            op.Signal("slow-response");
    }
    catch (RateLimitException ex)
    {
        op.Signal("rate-limit");
        op.Signal($"rate-limit:{ex.RetryAfterMs}ms");
        throw;
    }
    catch (TimeoutException)
    {
        op.Signal("timeout");
        throw;
    }
});
```

信号只是字符串 @ . @ 使用简单名称@ MS K1 @`"rate-limit"`)或结构化名称 @(`"rate-limit:5000ms"`).
模式过滤器使用 glob 语义表达式@ ( @%`*`, `?`支持逗号列表@( @%`"error.*,timeout"`). 匹配是决定性的和分配@-jlight `StringPatternMatcher`.

### Fineó- 信号示例@ : HTTP 呼叫

对于非常详细的可观测性来说 , 您可以在操作的每个阶段发出信号 *.图书馆包括一个样本 [信号提示服务](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Examples/SignalingHttpClient.cs) 显示此模式的图案@: @%

```csharp
using Mostlylucid.Helpers.Ephemeral.Examples;

// Inside your work body where you have access to the operation's emitter:
await coordinator.ProcessAsync(async (request, op, ct) =>
{
    var data = await SignalingHttpClient.DownloadWithSignalsAsync(
        httpClient,
        new HttpRequestMessage(HttpMethod.Get, request.Url),
        op,  // ISignalEmitter
        ct);

    // Process the downloaded data...
});
```

它在每个阶段发出信号 :

@| 信号 | 当#|
|--------|------|
| `stage.starting` @|在请求开始之前@|
| `progress:0` @|_ 初步进展标志#|}
| `stage.request` |+HTTP请求已发送@|+#
| `stage.headers` @| 反应头目收到#|
| `stage.reading` 开始阅读正文 @|}
| `progress:XX` @|_progress 百分率(0-100)}下载时的进度%{|}
| `stage.completed` | 下载完成 @|

然后,您可以使用匹配:}的图案查询这些 。

```csharp
// Find all stage transitions
var stages = coordinator.GetSignalsByPattern("stage.*");

// Check download progress
var progress = coordinator.GetSignalsByPattern("progress:*");

// Check if any download is still in progress
if (coordinator.HasSignalMatching("stage.reading") &&
    !coordinator.HasSignalMatching("stage.completed"))
{
    // Download in progress
}
```

### 正在压缩信号

操作还可以删除自己的信号@. 这对临时状态有用 @:

```csharp
await coordinator.ProcessAsync(async (item, op, ct) =>
{
    // Mark as processing
    op.Emit("processing");

    try
    {
        await ProcessItemAsync(item, ct);

        // Success - retract the processing signal
        op.Retract("processing");
        op.Emit("completed");
    }
    catch (RetryableException)
    {
        // Keep processing signal, add retry info
        op.Emit("retrying");
    }
    catch (Exception)
    {
        // Remove all temporary signals
        op.RetractMatching("processing*");
        op.Emit("failed");
        throw;
    }
});
```

### 递减事件

就像信号发射一样 , 撤回可以触发回调@:\ *

```csharp
var coordinator = new EphemeralWorkCoordinator<Request>(
    body,
    new EphemeralOptions
    {
        // Sync retraction handler
        OnSignalRetracted = evt =>
        {
            _metrics.DecrementGauge(evt.Signal);
            Console.WriteLine($"Signal {evt.Signal} retracted from op {evt.OperationId}");

            if (evt.WasPatternMatch)
                Console.WriteLine($"  (matched pattern: {evt.Pattern})");
        },

        // Async retraction handler
        OnSignalRetractedAsync = async (evt, ct) =>
        {
            await _telemetry.TrackRetraction(evt.Signal, evt.OperationId, ct);
        }
    });
```

缩略 `SignalRetractedEvent` 包括:

- `Signal` - 收回的信号名称
- `OperationId` {\fn华文楷体\fs16\1cHE0E0E0}收回的操作
- `Key` - 操作' 键MS K2 任何□
- `Timestamp` 当撤回发生时 -
- `WasPatternMatch` # - 若被翻转, 则正确 # `RetractMatching`
- `Pattern` - 使用的模式@(if 模式匹配 @)

### 真实-世界示例_:恢复率限制

```csharp
await coordinator.ProcessAsync(async (request, op, ct) =>
{
    // Check if we already have a rate limit signal
    if (op.HasSignal("rate-limited"))
    {
        // We're in recovery mode
        await Task.Delay(1000, ct);
    }

    try
    {
        var response = await _api.SendAsync(request, ct);

        // Success! Remove any rate limit signal
        if (op.Retract("rate-limited"))
        {
            op.Emit("rate-limit-cleared");
        }
    }
    catch (RateLimitException ex)
    {
        op.Emit("rate-limited");
        op.Emit($"rate-limit:{ex.RetryAfterMs}ms");
        throw;
    }
});
```

---


## 遥感信号

所有协调员都提供最佳的信号查询@: @%

```csharp
// Check if any recent operation hit a rate limit
if (coordinator.HasSignal("rate-limit"))
{
    await Task.Delay(1000);
}

// Count slow responses in the window
var slowCount = coordinator.CountSignals("slow-response");
if (slowCount > 10)
{
    await ThrottleAsync();
}

// Get signals by pattern
var httpErrors = coordinator.GetSignalsByPattern("http.error.*");

// Get signals since a time
var recentSignals = coordinator.GetSignalsSince(DateTimeOffset.UtcNow.AddMinutes(-1));

// Get signals for a specific key
var userSignals = coordinator.GetSignalsByKey("user-123");
```

---


## 信号@- @反应处理

从 [时间选择@. @cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/EphemeralOptions.cs):

协调员可以自动对信号响应@: @%

```csharp
var coordinator = new EphemeralWorkCoordinator<Request>(
    body,
    new EphemeralOptions
    {
        // Cancel new work if these signals are present
        CancelOnSignals = new HashSet<string> { "system-overload", "circuit-open" },

        // Defer new work while these signals are present
        DeferOnSignals = new HashSet<string> { "rate-limit" },
        MaxDeferAttempts = 10,
        DeferCheckInterval = TimeSpan.FromMilliseconds(100)
    });
```

当信号在 `CancelOnSignals` 被检测到\,}% 跳过的新项目@ (} 计为失败{).} @
当信号在 `DeferOnSignals` 检测到@,新项目,等待信号清除后 @.

---


## 适应率限制

从 [适应转换服务 @.%cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Examples/AdaptiveTranslationService.cs):

```csharp
public class AdaptiveTranslationService : IAsyncDisposable
{
    private readonly EphemeralWorkCoordinator<TranslationRequest> _coordinator;
    private readonly ITranslationApi _translationApi;

    public AdaptiveTranslationService(ITranslationApi translationApi)
    {
        _translationApi = translationApi;

        _coordinator = new EphemeralWorkCoordinator<TranslationRequest>(
            ProcessTranslationAsync,
            new EphemeralOptions
            {
                MaxConcurrency = 8,
                MaxTrackedOperations = 100,

                // New work is deferred while any "rate-limit" or "rate-limit:*" signal is present
                DeferOnSignals = new HashSet<string> { "rate-limit", "rate-limit:*" },
                MaxDeferAttempts = 10,
                DeferCheckInterval = TimeSpan.FromMilliseconds(100)
            });
    }

    public async Task TranslateAsync(TranslationRequest request)
    {
        // Optional: extra politeness based on most recent retry-after
        var rateLimitSignals = _coordinator.GetSignalsByPattern("rate-limit:*");
        if (rateLimitSignals.Count > 0)
        {
            var latest = rateLimitSignals
                .OrderByDescending(s => s.Timestamp)
                .First()
                .Signal; // "rate-limit:5000ms"

            if (TryParseRetryAfter(latest, out var delay))
            {
                await Task.Delay(delay);
            }
        }

        await _coordinator.EnqueueAsync(request);
    }

    public static bool TryParseRetryAfter(string signal, out TimeSpan delay)
    {
        delay = default;
        var parts = signal.Split(':', 2);
        if (parts.Length != 2) return false;

        var payload = parts[1].Trim();
        if (!payload.EndsWith("ms", StringComparison.OrdinalIgnoreCase)) return false;

        var numPart = payload[..^2];
        if (!int.TryParse(numPart, out var ms) || ms < 0) return false;

        delay = TimeSpan.FromMilliseconds(ms);
        return true;
    }
}
```

当速率限制被击中时,此服务的每个实例都会自动后退@ . @ no shared state\ .}没有传递消息 passing._ 刚刚读取时间窗口@.}

---


## 真正的-世界实例 :交叉-协调员意识

多个协调员可以通过共同的交流相互感觉 `SignalSink`:

```csharp
public class OrderProcessingSystem
{
    private readonly SignalSink _sharedSignals = new(maxCapacity: 1000);

    private readonly EphemeralWorkCoordinator<Order> _orderProcessor;
    private readonly EphemeralWorkCoordinator<PaymentRequest> _paymentProcessor;

    public OrderProcessingSystem()
    {
        var options = new EphemeralOptions { Signals = _sharedSignals };

        _orderProcessor = new EphemeralWorkCoordinator<Order>(
            ProcessOrderAsync, options);

        _paymentProcessor = new EphemeralWorkCoordinator<PaymentRequest>(
            ProcessPaymentAsync, options);
    }

    public async Task ProcessOrderAsync(Order order)
    {
        // Check shared signals for payment gateway issues
        if (_sharedSignals.Detect("gateway-error"))
        {
            await _retryQueue.EnqueueAsync(order);
            return;
        }

        await _orderProcessor.EnqueueAsync(order);
    }
}
```

---


## 健康监测

```csharp
[HttpGet("/health/detailed")]
public IActionResult GetDetailedHealth()
{
    return Ok(new
    {
        translation = new
        {
            pending = _translationCoordinator.PendingCount,
            active = _translationCoordinator.ActiveCount,
            recentRateLimits = _translationCoordinator.CountSignals("rate-limit"),
            recentTimeouts = _translationCoordinator.CountSignals("timeout"),
            recentSuccess = _translationCoordinator.CountSignals("success"),
            hasErrors = _translationCoordinator.HasSignalMatching("error.*")
        },
        payment = new
        {
            pending = _paymentCoordinator.PendingCount,
            gatewayErrors = _paymentCoordinator.CountSignals("gateway-error"),
            declines = _paymentCoordinator.CountSignals("declined"),
            approvals = _paymentCoordinator.CountSignals("approved")
        }
    });
}
```

不需要量度库@ . @ 只要查询时间窗口@ MPK1 @

---


## RealQ-世界示例 :信号-基于电路断线

从 [基于信号的圆环环境Breaker @ . @ ccs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Examples/SignalBasedCircuitBreaker.cs):

```csharp
public class SignalBasedCircuitBreaker
{
    private readonly string _failureSignal;
    private readonly int _threshold;
    private readonly TimeSpan _windowSize;

    public SignalBasedCircuitBreaker(
        string failureSignal = "failure",
        int threshold = 5,
        TimeSpan? windowSize = null)
    {
        _failureSignal = failureSignal;
        _threshold = threshold;
        _windowSize = windowSize ?? TimeSpan.FromSeconds(30);
    }

    public bool IsOpen<T>(EphemeralWorkCoordinator<T> coordinator)
    {
        var recentFailures = coordinator.GetSignalsSince(
            DateTimeOffset.UtcNow - _windowSize);

        return recentFailures.Count(s => s.Signal == _failureSignal) >= _threshold;
    }

    public int GetFailureCount<T>(EphemeralWorkCoordinator<T> coordinator)
    {
        var recentFailures = coordinator.GetSignalsSince(
            DateTimeOffset.UtcNow - _windowSize);

        return recentFailures.Count(s => s.Signal == _failureSignal);
    }
}

// Usage
var circuitBreaker = new SignalBasedCircuitBreaker("api-error", threshold: 3);

if (circuitBreaker.IsOpen(_coordinator))
{
    throw new CircuitOpenException("Too many recent API errors");
}

await _coordinator.EnqueueAsync(request);
```

断路器没有其自身的状态 @-}它只是读过时间窗口@.

---


## 防止无限环圈

从 [信号@.%cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Signals.cs):

当信号能引起其他信号时 , 你冒着无穷的冒险 `SignalConstraints` 防止此选项@ : @ {}

```csharp
var options = new EphemeralOptions
{
    SignalConstraints = new SignalConstraints
    {
        // Max propagation depth before blocking
        MaxDepth = 10,

        // Prevent A → B → A cycles
        BlockCycles = true,

        // Signals that end propagation chains
        TerminalSignals = new HashSet<string> { "completed", "failed", "resolved" },

        // Signals that emit but don't propagate
        LeafSignals = new HashSet<string> { "logged", "metric" },

        // Callback when a signal is blocked
        OnBlocked = (signal, reason) =>
        {
            _logger.LogWarning("Signal {Signal} blocked: {Reason}",
                signal.Signal, reason);
        }
    }
};
```

### 信号传动

音轨因果关系 `EmitCaused`:

```csharp
public void HandleSignal(SignalEvent evt, ISignalEmitter emitter)
{
    if (evt.Is("order-placed"))
    {
        // This signal carries the propagation chain
        // Will be blocked if it would create a cycle
        emitter.EmitCaused("inventory-reserved", evt.Propagation);
    }
}
```

传播链跟踪路径 #:# `order-placed → inventory-reserved → ...`

如果 `inventory-reserved` 尝试发送 `order-placed`@, 它将被屏蔽\ ( 循环检测\ ).\ {

---


## 全球信号空间

从 [信号@.%cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Signals.cs):

需要在所有协调员中看到这些信号吗?

```csharp
public sealed class SignalSink
{
    private readonly ConcurrentQueue<SignalEvent> _window;
    private readonly int _maxCapacity;
    private readonly TimeSpan _maxAge;

    public SignalSink(int maxCapacity = 1000, TimeSpan? maxAge = null);

    // Raise signals
    public void Raise(SignalEvent signal);
    public void Raise(string signal, string? key = null);

    // Sense signals
    public IReadOnlyList<SignalEvent> Sense();
    public IReadOnlyList<SignalEvent> Sense(Func<SignalEvent, bool> predicate);
    public bool Detect(string signalName);
    public bool Detect(Func<SignalEvent, bool> predicate);

    public int Count { get; }
}
```

用法@: @%

```csharp
// Create a shared sink
var sink = new SignalSink(maxCapacity: 1000, maxAge: TimeSpan.FromMinutes(2));

// Configure coordinators to use it
var options = new EphemeralOptions { Signals = sink };

// Or raise signals directly
sink.Raise("system-maintenance");

// Sense from anywhere
if (sink.Detect("system-maintenance"))
{
    await DeferWorkAsync();
}
```

---


## 与字符串匹配模式

从 [字符串父书签@. @cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/StringPatternMatcher.cs):

用于信号过滤的 Glob-样式匹配@ :

```csharp
// Exact match
coordinator.HasSignal("rate-limit");

// Wildcard patterns
coordinator.HasSignalMatching("http.*");           // http.timeout, http.error
coordinator.HasSignalMatching("error.*.critical"); // error.payment.critical
coordinator.HasSignalMatching("user-???-failed");  // user-123-failed

// Comma-separated patterns in CancelOnSignals/DeferOnSignals
new EphemeralOptions
{
    CancelOnSignals = new HashSet<string>
    {
        "system-overload, circuit-open",  // Either pattern
        "error.*"                          // Any error signal
    }
}
```

---


## 信号命名公约

保持信号简单和一致 *:*

```csharp
// Good - simple, categorical
op.Signal("success");
op.Signal("failure");
op.Signal("rate-limit");
op.Signal("timeout");
op.Signal("cache-hit");

// Good - structured for parsing
op.Signal("rate-limit:5000ms");
op.Signal("retry:attempt-3");
op.Signal("slow:2500ms");
op.Signal("http.error:429");

// Good - hierarchical for pattern matching
op.Signal("payment.declined");
op.Signal("payment.approved");
op.Signal("payment.gateway-error");

// Avoid - entity identification belongs in Key, not signals
op.Signal("user-123-rate-limited");  // Bad

// Instead
op.Key = "user-123";
op.Signal("rate-limit");
```

---


## Async 信号处理

同步信号处理器 @ ( @`OnSignal`@ )_ 运行在操作中@ MS K1} 连接 —\ kkeep them fast * .} 要将信号发送到同步路径 `SignalDispatcher` (+#模式匹配@,_确定性顺序 @)}或 `AsyncSignalProcessor`.

### 发送信号的粉丝@- @%out

```csharp
await using var dispatcher = new SignalDispatcher(new EphemeralOptions
{
    MaxConcurrency = Environment.ProcessorCount,
    MaxConcurrencyPerKey = 1  // sequential per signal name by default
});

dispatcher.Register("error.*", evt => _alerts.SendAsync(evt.Signal));
dispatcher.Register("progress:*", evt => _metrics.Record(evt.Signal));

// In coordinator options, keep OnSignal cheap and enqueue
var coordinator = new EphemeralWorkCoordinator<Request>(
    body,
    new EphemeralOptions
    {
        OnSignal = dispatcher.Dispatch
    });
```

模式支助 `*`, `?`@,和逗号列表@(`"error.*,timeout"`).所有匹配的处理器都按注册顺序运行 在背景密钥协调员\; emit 仍然同步@.

### Async 信号处理器

用于独立自动同步处理@: @%

```csharp
await using var processor = new AsyncSignalProcessor(
    async (signal, ct) =>
    {
        await _externalService.LogAsync(signal, ct);
    },
    maxConcurrency: 4,
    maxQueueSize: 1000);

// Enqueue signals (returns immediately)
processor.Enqueue(new SignalEvent(
    "rate-limit",
    operationId,
    key,
    DateTimeOffset.UtcNow));
```

### 遥测信号Handler示例

将合成信号处理与遥测集成相结合的完整示例@:

> **资料来源::** [遥测信号Handler @.%cs](https://github.com/scottgal/mostlylucidweb/blob/main/Mostlylucid/Helpers/Ephemeral/Examples/TelemetrySignalHandler.cs)

```csharp
public class TelemetrySignalHandler : IAsyncDisposable
{
    private readonly AsyncSignalProcessor _processor;
    private readonly ITelemetryClient _telemetry;

    public TelemetrySignalHandler(ITelemetryClient telemetry)
    {
        _telemetry = telemetry;
        _processor = new AsyncSignalProcessor(
            HandleSignalAsync,
            maxConcurrency: 8,
            maxQueueSize: 5000);
    }

    // Synchronous entry point - returns immediately
    public bool OnSignal(SignalEvent signal) => _processor.Enqueue(signal);

    private async Task HandleSignalAsync(SignalEvent signal, CancellationToken ct)
    {
        var properties = new Dictionary<string, string>
        {
            ["signal"] = signal.Signal,
            ["operationId"] = signal.OperationId.ToString(),
            ["key"] = signal.Key ?? "none"
        };

        await _telemetry.TrackEventAsync("EphemeralSignal", properties, ct);

        // Categorized tracking based on signal prefix
        if (signal.StartsWith("error"))
            await _telemetry.TrackExceptionAsync(signal.Signal, properties, ct);
        else if (signal.StartsWith("perf"))
            await _telemetry.TrackMetricAsync(signal.Signal, 1, ct);
    }

    // Expose stats for monitoring
    public int QueuedCount => _processor.QueuedCount;
    public long ProcessedCount => _processor.ProcessedCount;
    public long DroppedCount => _processor.DroppedCount;

    public async ValueTask DisposeAsync() => await _processor.DisposeAsync();
}
```

连线给你的协调员

```csharp
await using var telemetryHandler = new TelemetrySignalHandler(telemetryClient);

await using var coordinator = new EphemeralWorkCoordinator<Request>(
    ProcessAsync,
    new EphemeralOptions
    {
        OnSignal = signal => telemetryHandler.OnSignal(signal)
    });
```

处理器:

- **永无区块** 操作线索@- @% `OnSignal` 立即返回
- **信号分类** 不同的遥测类型前缀
- **度量** @(Qqueued@,}经处理 *,* 丢弃=)* 用于健康监测
- **间距内存** 如果队列填满, - 降下最古老的信号

---


## 为何这样工作

信号是强大的,因为 它们 @'re **短时间**:

-=YTET -伊甸园字幕组=- 翻译:
|----------|---------|
| **环形** {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}老讯号年龄已经过时
| **自 己-清洁** @| 不需要清理代码@|
| **分离** @|_Eniters don't know about listens \ |}#MSK2# #知道听众的消息吗?
| **可观察** 任何代码都能感知到当前状态 @| @
| **私营** @|没有用户数据\ -只是信号名@|
| **快速快** @|O(1) 检测短MS K2 路由@|#

缩略语窗口已经存在用于调试@. @signals just give it 语义意为 @.}

---


## 结论结论

信号将孤立的处决原子变成 **遥感网络**每一个协调员都能够

- **埃米特** 有关其经历的信号
- **感知** 来自其本身历史或共有汇的信号
- **反应反应** 自动通过 `CancelOnSignals` 和 `DeferOnSignals`

无信件中介@.无共享状态 @.无协调协议\ .仅使用自然衰减的元数据操作=.

原子会直接和对方交谈 - 他们只是在时间窗口留下痕迹 其他人可以观察它们

**Fire ... 信号... Sense @... 忘了.**

---


## 链接链接链接

- [部分#1:火和唐・'t *不错* 忘记](/blog/fire-and-dont-quite-forget-ephemeral-execution) 理论和模式
- [建立可重复使用的短时执行图书馆](/blog/ephemeral-execution-library) *-* 全面执行
- [{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}斯格梅吉 ( 维基佩迪亚 MS K1 *](https://en.wikipedia.org/wiki/Stigmergy) 通过环境改变进行间接协调
- [电路断开器模式](https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
- [反反应扩展](https://github.com/dotnet/reactive)