Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snapshots table exploding #359

Closed
AidasK opened this issue Aug 16, 2022 · 2 comments
Closed

Snapshots table exploding #359

AidasK opened this issue Aug 16, 2022 · 2 comments

Comments

@AidasK
Copy link

AidasK commented Aug 16, 2022

Our snapshots table now contains 9 000 000 records and they take up 160gb of space. Is there a command which could cleanup old snapshot versions? Thanks

@AidasK
Copy link
Author

AidasK commented Aug 16, 2022

Would you accept this pull request? It ensures that all old snapshots would get deleted after a new one was created.
EloquentSnapshotRepository.php:

    public function persist(Snapshot $snapshot): Snapshot
    {
        /** @var \Spatie\EventSourcing\Snapshots\EloquentSnapshot $eloquentSnapshot */
        $eloquentSnapshot = new $this->snapshotModel();

        $eloquentSnapshot->aggregate_uuid = $snapshot->aggregateUuid;
        $eloquentSnapshot->aggregate_version = $snapshot->aggregateVersion;
        $eloquentSnapshot->state = $snapshot->state;

        $eloquentSnapshot->save();

        $snapshts = $eloquentSnapshot::query()
            ->where('aggregate_uuid', $snapshot->aggregateUuid)
            ->where('aggregate_version', '<', $snapshot->aggregateVersion)
            ->oldest()
            ->limit(5)
            ->pluck('id');
        $eloquentSnapshot::query()->whereIn('id', $ids)->delete();

        return $eloquentSnapshot->toSnapshot();
    }

Notice that I have also added a limit to this query. Probably at this point some aggregate roots might have more than 1000 snapshots and we don't want to timeout these requests.

I am not doing a simple query like below, since mysql performs best, then delete is performed on unique index. I want to avoid gap locking at any cost. Also aggregate_version column has no index and that might create a lock on entire table.

        $this->snapshotModel()
             ->query()
             ->where('aggregate_uuid', $snapshot->aggregateUuid)
             ->where('aggregate_version', '<', $snapshot->aggregateVersion)
             ->delete();

Drawbacks? Migration period might create some temporary latencies while each aggregate root is performing snapshot cleanup.

@AidasK
Copy link
Author

AidasK commented Aug 16, 2022

Probably we don't even need all of this logic anymore as we could just update one record each time. We could not do this in earlier versions of laravel as upsert method was introduced only recently. Though for this to work we would also need to add unique index on snapshots.aggregate_uuid and that would be a breaking change. Entire application would need to stop to clear duplicate records and to add a new index, it does not sound easy.

$this->snapshotModel()->upsert([
    'aggregate_uuid' => $snapshot->aggregateUuid, 
    'aggregate_version' => $snapshot->aggregateVersion,
    'state' => $snapshot->state,
], ['aggregate_uuid'], ['aggregate_version', 'state', 'updated_at']);

I would be willing to create a pull requests with all of these strategies and tests and make it configurable via config.

@spatie spatie locked and limited conversation to collaborators Aug 19, 2022
@freekmurze freekmurze converted this issue into discussion #361 Aug 19, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant