bottledcode / durable-php
Requires
- php: >=8.3
- adhocore/cli: ^1.7.1
- amphp/file: ^3.1.0
- amphp/http-client: ^5.1.0
- amphp/log: ^v2.0.0
- amphp/parallel: ^2.2.9
- crell/serde: ^1.1.0
- nesbot/carbon: >2.0
- php-di/php-di: ^7.0.6
- ramsey/uuid: ^4.7.6
- webonyx/graphql-php: ^15.11.1
- withinboredom/time: ^4.0.3
Requires (Dev)
- laravel/pint: ^1.15.3
- mockery/mockery: ^1.6.11
- pestphp/pest: ^2.34.7
This package is auto-updated.
Last update: 2024-09-27 07:38:50 UTC
README
这是一个允许构建全球、分布式和持久性PHP应用的框架/库。它受到了几个微软项目的启发
以及Akka、Erlang等其他基于actor的框架。
它是什么?
Durable PHP是一个框架/库,允许你构建持久性分布式应用。持久性意味着应用可以承受单个组件的失败,并且应用可以在不中断服务的情况下进行扩展和缩减。Durable PHP使用RethinkDb或Redis作为底层存储。
它是如何工作的?
Durable PHP的构建块被称为“活动”。活动是一个无状态的类,实现了一个方法或可调用的功能。活动可以调用其他活动、进行计算、执行I/O操作和等待事件。活动由工作进程执行。工作进程负责执行活动并在数据库中存储活动的状态。
“编排”建立在活动之上。编排是一个有状态的类或方法,可以调用其他编排和活动。编排的状态存储在数据库中,状态是通过“回放”编排来重建的。因此,不建议在编排中进行I/O操作,因为这将执行多次。
“actor”建立在编排之上。actor是一个有状态的类或方法,可以调用其他actor、执行I/O操作和等待事件。actor的状态存储在数据库中,状态是通过填充actor来重建的。
这与常规PHP有何不同?
常规PHP是无状态的。这意味着每个请求都由一个新的PHP进程处理。这对于性能和可扩展性来说很好,但它使得构建需要维护状态的应用变得困难——通常涉及ORM和加载状态的仪式。Durable PHP允许你构建可以维护状态的应用,并且可以承受单个组件的失败。Durable PHP还设计用于在分布式环境中使用,其中多个PHP进程在不同的机器上运行,不会发生死锁。
这与其他PHP框架有何不同?
Durable PHP鼓励丰富的模型和领域驱动设计(DDD)。这意味着你可以使用代表你领域的类和方法来构建你的应用。
我能看到一个示例吗?
想象一下,你想上传一个文件到S3并等待文件处理完成,然后向用户发送邮件或如果发生错误或耗时过长,则向管理员发送邮件。没有Durable-PHP,这将非常复杂。以下是使用Durable-PHP的示例:
# SendEmailActivity.php class SendEmailActivity { public function __invoke(string $to, string $subject, string $body) { // Send email } } # UploadEntityInterface.php interface UploadEntityInterface { public function getFileUrl(): string; public function setProcessState(string $state): void; public function getProcessState(): string; } # UploadEntity.php class UploadEntity extends \Bottledcode\DurablePhp\State\EntityState implements UploadEntityInterface { public function __construct(private string $url, private string $state = 'pending') {} public function setProcessState(string $state): void { $this->state = $state; } public function getProcessState(): string { return $this->state; } } # UploadOrchestration.php class UploadOrchestration { public function __construct(private \Bottledcode\DurablePhp\OrchestrationContextInterface $context) {} public function __invoke(string $url) { $ctx = $this->context(); $uploadId = $ctx->newUuid(); // get a future that will be resolved when the upload is processed $signal = $context->waitForExternalEvent('upload-processed'); // get a future that will be resolved when the timer expires (one hour from now) $timeout = $context->createTimer($context->getCurrentTime()->add(new DateInterval('PT1H'))) // wait for the upload to be processed or the timer to expire $winner = $context->waitAny($signal, $timeout); if($winner === $signal) { // upload was processed $ctx->signal($uploadId, fn(UploadEntity $entity) => $entity->setProcessState('processed')); $context->callActivity(SendEmailActivity::class, ['to' => 'user', 'subject' => 'Upload processed', 'body' => 'Your upload was processed']); } else { // upload was not processed $ctx->signal($uploadId, fn(UploadEntity $entity) => $entity->setProcessState('timed-out')); $context->callActivity(SendEmailActivity::class, ['to' => 'admin', 'subject' => 'Upload failed', 'body' => 'The upload timed out']); } } }
我该如何使用它?
这远未达到生产就绪状态,所以如果你想使用它,请做好准备,因为可能会出现故障或在没有太多警告的情况下进行大幅更改。如果你在使用,请通过问题反馈给我。我很乐意了解它的使用情况和用途。