Skip to content

Commit 2c8a450

Browse files
author
Richard McDaniel
committed
Alpha version
0 parents  commit 2c8a450

28 files changed

+852
-0
lines changed

.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
APP_KEY=base64:i3g6f+dV8FfsIkcxqd7gbiPn2oXk5r00sTmdD6V5utI=
2+
3+
DB_CONNECTION=mysql
4+
DB_DATABASE=testbench
5+
DB_HOST=127.0.0.1
6+
DB_PORT=3306
7+
DB_USERNAME=root
8+
DB_PASSWORD=password
9+
10+
QUEUE_CONNECTION=redis
11+
12+
REDIS_HOST=127.0.0.1
13+
REDIS_PASSWORD=
14+
REDIS_PORT=6379

.github/workflows/php.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: PHP Composer
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
14+
services:
15+
mysql:
16+
image: mysql
17+
env:
18+
MYSQL_ROOT_PASSWORD: password
19+
ports:
20+
- 3306:3306
21+
22+
redis:
23+
image: redis
24+
ports:
25+
- 6379:6379
26+
27+
steps:
28+
- uses: actions/checkout@v2
29+
30+
- name: Validate composer.json and composer.lock
31+
run: composer validate --strict
32+
33+
- name: Cache Composer packages
34+
id: composer-cache
35+
uses: actions/cache@v2
36+
with:
37+
path: vendor
38+
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
39+
restore-keys: |
40+
${{ runner.os }}-php-
41+
42+
- name: Install dependencies
43+
run: composer install --prefer-dist --no-progress
44+
45+
- name: Create database
46+
run: mysql -e 'CREATE DATABASE testbench' -h127.0.0.1 -uroot -ppassword -P ${{ job.services.mysql.ports[3306] }}
47+
48+
- name: Run test suite
49+
run: composer run-script test
50+
env:
51+
APP_KEY: base64:i3g6f+dV8FfsIkcxqd7gbiPn2oXk5r00sTmdD6V5utI=
52+
DB_CONNECTION: mysql
53+
DB_DATABASE: testbench
54+
DB_HOST: 127.0.0.1
55+
DB_PORT: 3306
56+
DB_USERNAME: root
57+
DB_PASSWORD: password
58+
QUEUE_CONNECTION: redis
59+
REDIS_HOST: 127.0.0.1
60+
REDIS_PASSWORD:
61+
REDIS_PORT: 6379

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
build
2+
composer.lock
3+
vendor
4+
coverage
5+
.env
6+
.phpunit.result.cache
7+
.php_cs.cache
8+
.php-cs-fixer.cache

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Laravel Workflow [![PHP Composer](https://github.com/laravel-workflow/laravel-workflow/actions/workflows/php.yml/badge.svg)](https://github.com/laravel-workflow/laravel-workflow/actions/workflows/php.yml)
2+
3+
Durable workflow engine that allows users to write long running persistent distributed workflows (orchestrations) in PHP powered by [Laravel queues](https://laravel.com/docs/9.x/queues).
4+
5+
## Installation
6+
7+
This library is installable via [Composer](https://getcomposer.org).
8+
9+
```bash
10+
composer require laravel-workflow/laravel-workflow
11+
```
12+
13+
## Requirements
14+
15+
You can use any queue driver that Laravel supports but this is heavily tested against Redis.
16+
17+
## Usage
18+
19+
**1. Create a workflow.**
20+
```php
21+
class MyWorkflow extends Workflow
22+
{
23+
public function execute()
24+
{
25+
$result = yield ActivityStub::make(MyActivity::class);
26+
return $result;
27+
}
28+
}
29+
```
30+
31+
**2. Create an activity.**
32+
```php
33+
class MyActivity extends Activity
34+
{
35+
public function execute()
36+
{
37+
return 'activity';
38+
}
39+
}
40+
```
41+
42+
**3. Run the workflow.**
43+
```php
44+
$workflow = WorkflowStub::make(MyWorkflow::class);
45+
$workflow->start();
46+
while ($workflow->running());
47+
$workflow->output();
48+
=> 'activity'
49+
```
50+
51+
## Failed Workflows
52+
53+
If a workflow fails or crashes at any point then it can be resumed from that point. Any activities that were successfully completed during the previous execution of the workflow will not be ran again.
54+
55+
```php
56+
$workflow = WorkflowStub::load(1);
57+
$workflow->reset();
58+
$workflow->start();
59+
while ($workflow->running());
60+
$workflow->output();
61+
=> 'activity'
62+
```
63+
64+
## Retries
65+
66+
A workflow will only fail when the retries on the workflow or a failing activity have been exhausted.
67+
68+
Workflows and activies are based on Laravel jobs so you can use any options you normally would.
69+
70+
```php
71+
public $tries = 3;
72+
73+
public $maxExceptions = 3;
74+
```

artisan

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
define('LARAVEL_START', microtime(true));
5+
6+
/*
7+
|--------------------------------------------------------------------------
8+
| Register The Auto Loader
9+
|--------------------------------------------------------------------------
10+
|
11+
| Composer provides a convenient, automatically generated class loader
12+
| for our application. We just need to utilize it! We'll require it
13+
| into the script here so that we do not have to worry about the
14+
| loading of any of our classes manually. It's great to relax.
15+
|
16+
*/
17+
18+
require __DIR__.'/vendor/autoload.php';
19+
20+
Dotenv\Dotenv::createImmutable(__DIR__)->safeLoad();
21+
22+
$app = require_once __DIR__.'/vendor/orchestra/testbench-core/laravel/bootstrap/app.php';
23+
24+
/*
25+
|--------------------------------------------------------------------------
26+
| Run The Artisan Application
27+
|--------------------------------------------------------------------------
28+
|
29+
| When we run the console application, the current CLI command will be
30+
| executed in this console and the response sent back to a terminal
31+
| or another output device for the developers. Here goes nothing!
32+
|
33+
*/
34+
35+
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
36+
37+
$status = $kernel->handle(
38+
$input = new Symfony\Component\Console\Input\ArgvInput,
39+
new Symfony\Component\Console\Output\ConsoleOutput
40+
);
41+
42+
/*
43+
|--------------------------------------------------------------------------
44+
| Shutdown The Application
45+
|--------------------------------------------------------------------------
46+
|
47+
| Once Artisan has finished running, we will fire off the shutdown events
48+
| so that any final work may be done by the application before we shut
49+
| down the process. This is the last thing to happen to the request.
50+
|
51+
*/
52+
53+
$kernel->terminate($input, $status);
54+
55+
exit($status);

composer.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "laravel-workflow/laravel-workflow",
3+
"description": "Durable workflow engine that allows users to write long running persistent distributed workflows (orchestrations) in PHP powered by Laravel queues.",
4+
"type": "library",
5+
"license": "MIT",
6+
"autoload": {
7+
"psr-4": {
8+
"Workflow\\": "src/"
9+
}
10+
},
11+
"autoload-dev": {
12+
"psr-4": {
13+
"Tests\\": "tests/"
14+
}
15+
},
16+
"scripts": {
17+
"test": "phpunit"
18+
},
19+
"authors": [
20+
{
21+
"name": "Richard McDaniel",
22+
"email": "richard.lee.mcdaniel@gmail.com"
23+
}
24+
],
25+
"require": {
26+
"spatie/laravel-model-states": "^2.1"
27+
},
28+
"require-dev": {
29+
"orchestra/testbench": "^7.1"
30+
},
31+
"extra": {
32+
"laravel": {
33+
"providers": [
34+
"Workflow\\WorkflowServiceProvider"
35+
]
36+
}
37+
}
38+
}

phpunit.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" backupStaticAttributes="false" colors="true" verbose="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
3+
<coverage>
4+
<include>
5+
<directory suffix=".php">src/</directory>
6+
</include>
7+
</coverage>
8+
<testsuites>
9+
<testsuite name="Workflow Test Suite">
10+
<directory>./tests/Feature</directory>
11+
</testsuite>
12+
</testsuites>
13+
<php>
14+
<ini name="memory_limit" value="-1"/>
15+
</php>
16+
</phpunit>

src/Activity.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Workflow;
4+
5+
use BadMethodCallException;
6+
use Illuminate\Bus\Queueable;
7+
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
8+
use Illuminate\Contracts\Queue\ShouldQueue;
9+
use Illuminate\Foundation\Bus\Dispatchable;
10+
use Illuminate\Queue\InteractsWithQueue;
11+
use Illuminate\Queue\SerializesModels;
12+
use Throwable;
13+
use Workflow\Middleware\WorkflowMiddleware;
14+
use Workflow\Models\StoredWorkflow;
15+
16+
class Activity implements ShouldBeEncrypted, ShouldQueue
17+
{
18+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
19+
20+
public $tries = 3;
21+
22+
public $maxExceptions = 3;
23+
24+
public $arguments;
25+
26+
public $index;
27+
28+
public $model;
29+
30+
public function __construct(int $index, StoredWorkflow $model, ...$arguments)
31+
{
32+
$this->index = $index;
33+
$this->model = $model;
34+
$this->arguments = $arguments;
35+
}
36+
37+
public function handle()
38+
{
39+
if (! method_exists($this, 'execute')) {
40+
throw new BadMethodCallException('Execute method mot implemented.');
41+
}
42+
43+
return $this->{'execute'}(...$this->arguments);
44+
}
45+
46+
public function middleware()
47+
{
48+
return [new WorkflowMiddleware()];
49+
}
50+
51+
public function failed(Throwable $exception)
52+
{
53+
$this->model->toWorkflow()->fail($exception);
54+
}
55+
}

src/ActivityStub.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Workflow;
4+
5+
class ActivityStub
6+
{
7+
protected $activity;
8+
9+
protected $arguments;
10+
11+
private function __construct($activity, ...$arguments)
12+
{
13+
$this->activity = $activity;
14+
$this->arguments = $arguments;
15+
}
16+
17+
public static function make($activity, ...$arguments)
18+
{
19+
return new static($activity, ...$arguments);
20+
}
21+
22+
public function activity()
23+
{
24+
return $this->activity;
25+
}
26+
27+
public function arguments()
28+
{
29+
return $this->arguments;
30+
}
31+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Workflow\Exceptions;
4+
5+
use Exception;
6+
7+
class WorkflowFailedException extends Exception
8+
{
9+
public function __construct($message = 'Workflow Failed.')
10+
{
11+
parent::__construct($message);
12+
}
13+
}

0 commit comments

Comments
 (0)