Skip to content

Commit

Permalink
Merge pull request #72 from tarfin-labs/WEB-4286-event-machine-json-a…
Browse files Browse the repository at this point in the history
…lanlarinin-boyutunu-azaltmak

WEB-4286: Event Machine: Reducing the size of context field
  • Loading branch information
deligoez authored Jan 8, 2024
2 parents 1ce5b93 + 04ed0e0 commit 225341d
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 7 deletions.
81 changes: 74 additions & 7 deletions src/Actor/Machine.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,37 @@ public function send(
*/
public function persist(): ?State
{
// Retrieve the previous context from the definition's config, or set it to an empty array if not set.
$incrementalContext = $this->definition->initializeContextFromState()->toArray();

// Get the last event from the state's history.
$lastHistoryEvent = $this->state->history->last();

MachineEvent::upsert(
values: $this->state->history->map(fn (MachineEvent $machineEvent) => array_merge($machineEvent->toArray(), [
'created_at' => $machineEvent->created_at->toDateTimeString(),
'machine_value' => json_encode($machineEvent->machine_value, JSON_THROW_ON_ERROR),
'payload' => json_encode($machineEvent->payload, JSON_THROW_ON_ERROR),
'context' => json_encode($machineEvent->context, JSON_THROW_ON_ERROR),
'meta' => json_encode($machineEvent->meta, JSON_THROW_ON_ERROR),
]))->toArray(),
values: $this->state->history->map(function (MachineEvent $machineEvent, int $index) use (&$incrementalContext, $lastHistoryEvent) {
// Get the context of the current machine event.
$changes = $machineEvent->context;

// If the current machine event is not the last one, compare its context with the incremental context and get the differences.
if ($machineEvent->id !== $lastHistoryEvent->id && $index > 0) {
$changes = $this->arrayRecursiveDiff($changes, $incrementalContext);
}

// If there are changes, update the incremental context to the current event's context.
if (!empty($changes)) {
$incrementalContext = $this->arrayRecursiveMerge($incrementalContext, $machineEvent->context);
}

$machineEvent->context = $changes;

return array_merge($machineEvent->toArray(), [
'created_at' => $machineEvent->created_at->toDateTimeString(),
'machine_value' => json_encode($machineEvent->machine_value, JSON_THROW_ON_ERROR),
'payload' => json_encode($machineEvent->payload, JSON_THROW_ON_ERROR),
'context' => json_encode($machineEvent->context, JSON_THROW_ON_ERROR),
'meta' => json_encode($machineEvent->meta, JSON_THROW_ON_ERROR),
]);
})->toArray(),
uniqueBy: ['id']
);

Expand Down Expand Up @@ -477,4 +500,48 @@ public function result(): mixed
$arguments ?? null,
);
}

// region Private Methods
/**
* Compares two arrays recursively and returns the difference.
*/
private function arrayRecursiveDiff(array $array1, array $array2): array
{
$difference = [];
foreach ($array1 as $key => $value) {
if (is_array($value)) {
if (!isset($array2[$key]) || !is_array($array2[$key])) {
$difference[$key] = $value;
} else {
$new_diff = $this->arrayRecursiveDiff($value, $array2[$key]);
if (!empty($new_diff)) {
$difference[$key] = $new_diff;
}
}
} elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) {
$difference[$key] = $value;
}
}

return $difference;
}

/**
* Merges two arrays recursively.
*/
protected function arrayRecursiveMerge(array $array1, array $array2): array
{
$merged = $array1;

foreach ($array2 as $key => &$value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = $this->arrayRecursiveMerge($merged[$key], $value);
} else {
$merged[$key] = $value;
}
}

return $merged;
}
// endregion
}
64 changes: 64 additions & 0 deletions tests/EventStoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

declare(strict_types=1);

use Tarfinlabs\EventMachine\Actor\Machine;
use Tarfinlabs\EventMachine\ContextManager;
use Tarfinlabs\EventMachine\Definition\EventDefinition;
use Tarfinlabs\EventMachine\Definition\MachineDefinition;
Expand Down Expand Up @@ -159,3 +160,66 @@
'in.transition.active.MUT.fail',
]);
});

it('stores incremental context', function (): void {
$machine = Machine::create([
'config' => [
'id' => 'traffic_light',
'initial' => 'green',
'context' => [
'count' => 1,
'value' => 'test',
],
'states' => [
'green' => [
'on' => [
'GREEN_TIMER' => [
'target' => 'yellow',
'actions' => 'changeCount',
],
],
],
'yellow' => [
'on' => [
'RED_TIMER' => [
'target' => 'red',
'actions' => 'changeValue',
],
],
],
'red' => [],
],
],
'behavior' => [
'actions' => [
'changeCount' => function (ContextManager $context): void {
$context->set('count', $context->get('count') + 1);
},
'changeValue' => function (ContextManager $context): void {
$context->set('value', 'retry');
},
],
],
]);

$machine->send(event: [
'type' => 'GREEN_TIMER',
]);

$newState = $machine->send(event: [
'type' => 'RED_TIMER',
]);

expect($newState->history)
->whereNotIn('type', [
'traffic_light.start',
'traffic_light.action.changeCount.finish',
'traffic_light.action.changeValue.finish',
'traffic_light.state.red.entry.finish',
])->each(fn ($event) => $event->context->toEqual([]))
->first()->context->toEqual(['data' => ['count' => 1, 'value' => 'test']])
->where('type', 'traffic_light.action.changeCount.finish')->first()->context->toEqual(['data' => ['count' => 2]])
->where('type', 'traffic_light.action.changeValue.finish')->first()->context->toEqual(['data' => ['value' => 'retry']])
->last()->context->toEqual(['data' => ['count' => 2, 'value' => 'retry']]);

});

0 comments on commit 225341d

Please sign in to comment.