gosuperscript / zero-downtime-event-replays
Spatie's Laravel 事件源包的零停机事件回放
dev-main
2024-08-15 10:25 UTC
Requires
- php: ^8.0
- illuminate/contracts: ^9.45|^10.0|^11.0
- spatie/laravel-event-sourcing: ^6.0|^7.0
- spatie/laravel-package-tools: ^1.4.3
Requires (Dev)
- nunomaduro/collision: ^6.0|^7.0|^8.0
- orchestra/testbench: ^7.0|^8.0|^9.0
- phpunit/phpunit: ^9.0|^10.0|^11.0
This package is auto-updated.
Last update: 2024-09-15 10:40:37 UTC
README
通常,在回放事件时,你可能需要处理一些可能导致停机的问题。你的读取模型将在回放开始时被截断,并且直到回放完成之前都不会有正确的数据。除此之外,你还必须等待将新记录的事件投影出去,直到回放完成,以保护回放顺序。
此包解决了这两个问题,允许对读取模型的副本进行回放。一旦回放加速,新记录的事件将被播放到两个投影中,以确保你的副本与实时读取模型保持同步。在验证新回放正确无误后,该包启用将回放提升到实时。结果是一个(几乎)零停机发布。
通常运行一个新的回复看起来像这样
- 创建一个新的回放,并给它一个键以识别它。例如 "add_extra_field_to_balance_projection"。你还可以在此步骤中指定你想要播放到的投影。
$manager = resolve(\Gosuperscript\ZeroDowntimeEventReplays\ReplayManager::class); // Create a replay $manager->createReplay('add_extra_field_to_balance_projection', [ "App\Projectors\BalanceProjector" ]);
- 可以开始回放。在回放过程中,它会调用投影器上的
useConnection
方法。这样投影器就知道应该将数据写入哪里。此包包含一个 EloquentZeroDowntimeProjector,它为处理不同的连接提供了一些魔法。
$manager->startReplay('add_extra_field_to_balance_projection');
- 一旦回放完成,但由于新记录的事件,生产环境中仍然存在一些延迟。你可以再次开始回放,它将从最新的投影事件开始。始终可以监控回放的状态和与生产的延迟。
// get the state & progress of your replay $manager->getReplay('add_extra_field_to_balance_projection'); // how many events is the replay behind the event stream? $manager->getReplayLag('add_extra_field_to_balance_projection');
- 一旦没有延迟,我们就可以开始将新事件投影到回放中。
$manager->startProjectingToReplay('add_extra_field_to_balance_projection');
- 一旦一切检查无误,你可以将回放提升到生产。
$manager->putReplayLive('add_extra_field_to_balance_projection');
- 最后,你可以清理你的回放
$manager->removeReplay('add_extra_field_to_balance_projection');
安装
您可以通过 composer 安装此包
composer require gosuperscript/zero-downtime-event-replays
用法
$manager = resolve(\Gosuperscript\ZeroDowntimeEventReplays\ReplayManager::class); // Create a replay $manager->createReplay('your_replay_key', ['projectorA', 'projectorB']); // Start replay history $manager->startReplay('your_replay_key'); // get the state & progress of your replay $manager->getReplay('your_replay_key'); // how many events is the replay behind the event stream? $manager->getReplayLag('your_replay_key'); // once a replay is up to date with the event stream, we can project events to it when they happen $manager->startProjectingToReplay('your_replay_key'); // Once the replay is approved, we can promote it to production $manager->putReplayLive('your_replay_key'); // Or we can delete the replay $manager->removeReplay('your_replay_key');
零停机投影器
为了使投影器与零停机回放一起工作,它们必须实现 ZeroDowntimeProjector
接口。此接口要求你实现以下方法
interface ZeroDowntimeProjector { // This method lets the projector know that its replaying on a replay public function forReplay(): self; // Sets the connection to replay to, using the replay key. Each connection must be treated as a clone of the production schema. public function useConnection(string $connection): self; // Promote your connection to production public function promoteConnectionToProduction(): void; // cleanup/remove connection public function removeConnection(); }
由于大多数投影可能都是回放到 eloquent,因此此包包含一个 EloquentZeroDowntimeProjector
抽象类和一个 Projectable
特性,用于你的 eloquent 读取模型。
为了使你的投影器与该包一起工作
- 确保你的投影器扩展了
EloquentZeroDowntimeProjector
。 - 在所有用于投影器的读取模型上添加
Projectable
特性。 - 在投影器上实现一个
models
方法,该方法返回投影器写入的所有模型。这由 EloquentZeroDowntimeProjector 用于设置正确的数据库模式和将正确的模型提升到生产。
public function models(): array { return [ new BalanceProjector(), ]; }
- 在查询或更新读取模型的所有地方,使用
forProjection
方法。
// when truncating Balance::forProjection($this->connection)->truncate(); // when querying Balance::forProjection($this->connection)->where('user_id', $event->user_id)->first(); // when updating Balance::forProjection($this->connection)->where('user_id', $event->user_id)->increment('total', $event->amount); // when newing an instance $balance = Balance::newForProjection($this->connection, ['id' => $event->user_id, 'total' => $event->amount]); $balance->save();
测试
composer test
变更日志
有关最近更改的更多信息,请参阅 CHANGELOG
贡献
有关详细信息,请参阅 CONTRIBUTING
安全漏洞
有关报告安全漏洞的详细信息,请参阅 我们的安全策略
致谢
许可
MIT许可(MIT)。请参阅许可文件获取更多信息。