Skip to content
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

[BC Break] Refactor #118

Merged
merged 5 commits into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 47 additions & 38 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,50 @@

## 0.5.0

Two new `bigint` columns were added to the `processed_messages` table:
`wait_time` and `handle_time`. These are milliseconds. You will need to
create a migration to add these columns to your database. They are not
nullable so your migration will need to account for existing data. You
can either truncate (purge) the `processed_messages` table or have your
migration calculate these values based on the existing data.

Here's a calculation example for MySQL:

```php
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class VersionXXX extends AbstractMigration
{
public function getDescription(): string
{
return 'Add processed_messages.wait_time and handle_time columns';
}

public function up(Schema $schema): void
{
// Add the columns as nullable
$this->addSql('ALTER TABLE processed_messages ADD wait_time BIGINT DEFAULT NULL, ADD handle_time BIGINT DEFAULT NULL');

// set the times from existing data
$this->addSql('UPDATE processed_messages SET wait_time = TIMESTAMPDIFF(SECOND, dispatched_at, received_at) * 1000, handle_time = TIMESTAMPDIFF(SECOND, received_at, finished_at) * 1000');

// Make the columns not nullable
$this->addSql('ALTER TABLE processed_messages CHANGE wait_time wait_time BIGINT NOT NULL, CHANGE handle_time handle_time BIGINT NOT NULL');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE processed_messages DROP wait_time, DROP handle_time');
}
}
```
* Two new `bigint` columns were added to the `processed_messages` table:
`wait_time` and `handle_time`. These are milliseconds. You will need to
create a migration to add these columns to your database. They are not
nullable so your migration will need to account for existing data. You
can either truncate (purge) the `processed_messages` table or have your
migration calculate these values based on the existing data.

Here's a calculation example for MySQL:

```php
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class VersionXXX extends AbstractMigration
{
public function getDescription(): string
{
return 'Add processed_messages.wait_time and handle_time columns';
}

public function up(Schema $schema): void
{
// Add the columns as nullable
$this->addSql('ALTER TABLE processed_messages ADD wait_time BIGINT DEFAULT NULL, ADD handle_time BIGINT DEFAULT NULL');

// set the times from existing data
$this->addSql('UPDATE processed_messages SET wait_time = TIMESTAMPDIFF(SECOND, dispatched_at, received_at) * 1000, handle_time = TIMESTAMPDIFF(SECOND, received_at, finished_at) * 1000');

// Make the columns not nullable
$this->addSql('ALTER TABLE processed_messages CHANGE wait_time wait_time BIGINT NOT NULL, CHANGE handle_time handle_time BIGINT NOT NULL');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE processed_messages DROP wait_time, DROP handle_time');
}
}
```
* `ProcessedMessage::timeInQueue()` now returns milliseconds instead of seconds.
* `ProcessedMessage::timeToHandle()` now returns milliseconds instead of seconds.
* `ProcessedMessage::timeToProcess()` now returns milliseconds instead of seconds.
* `Snapshot::averageWaitTime()` now returns milliseconds instead of seconds.
* `Snapshot::averageHandlingTime()` now returns milliseconds instead of seconds.
* `Snapshot::averageProcessingTime()` now returns milliseconds instead of seconds.
* The `results` column in the `processed_messages` table is now nullable. Create
a migration to capture this change. This is to allow for a future feature where
result processing/storage can be disabled.
2 changes: 1 addition & 1 deletion config/doctrine/mapping/ProcessedMessage.orm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
<field name="tags" column="tags" nullable="true" />
<field name="failureType" column="failure_type" nullable="true" />
<field name="failureMessage" column="failure_message" type="text" nullable="true" />
<field name="results" column="results" type="json" />
<field name="results" column="results" type="json" nullable="true" />
</mapped-superclass>
</doctrine-mapping>
4 changes: 2 additions & 2 deletions src/Command/MonitorCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ private function renderSnapshot(SymfonyStyle $io, InputInterface $input): void
$failRate < 10 => \sprintf('<comment>%s%%</comment>', $failRate),
default => \sprintf('<error>%s%%</error>', $failRate),
},
$waitTime ? Helper::formatTime($snapshot->averageWaitTime()) : 'n/a',
$handlingTime ? Helper::formatTime($snapshot->averageHandlingTime()) : 'n/a',
$waitTime ? Helper::formatTime($snapshot->averageWaitTime() / 1000) : 'n/a',
$handlingTime ? Helper::formatTime($snapshot->averageHandlingTime() / 1000) : 'n/a',
\round($snapshot->handledPerMinute(), 2),
\round($snapshot->handledPerHour(), 2),
\round($snapshot->handledPerDay(), 2),
Expand Down
76 changes: 76 additions & 0 deletions src/History/Metric.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

/*
* This file is part of the zenstruck/messenger-monitor-bundle package.
*
* (c) Kevin Bond <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Zenstruck\Messenger\Monitor\History;

/**
* @author Kevin Bond <[email protected]>
*/
abstract class Metric
{
final public function failRate(): float
{
try {
return $this->failureCount() / $this->totalCount();
} catch (\DivisionByZeroError) {
return 0;
}
}

/**
* @param positive-int $divisor Seconds
*/
final public function handledPer(int $divisor): float
{
$interval = $this->totalSeconds() / $divisor;

return $this->totalCount() / $interval;
}

final public function handledPerMinute(): float
{
return $this->handledPer(60);
}

final public function handledPerHour(): float
{
return $this->handledPer(60 * 60);
}

final public function handledPerDay(): float
{
return $this->handledPer(60 * 60 * 24);
}

/**
* @return int milliseconds
*/
final public function averageProcessingTime(): int
{
return $this->averageWaitTime() + $this->averageHandlingTime();
}

/**
* @return int milliseconds
*/
abstract public function averageWaitTime(): int;

/**
* @return int milliseconds
*/
abstract public function averageHandlingTime(): int;

abstract public function failureCount(): int;

abstract public function totalCount(): int;

abstract protected function totalSeconds(): int;
}
47 changes: 21 additions & 26 deletions src/History/Model/MessageTypeMetric.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,62 +11,57 @@

namespace Zenstruck\Messenger\Monitor\History\Model;

use Zenstruck\Messenger\Monitor\History\Metric;
use Zenstruck\Messenger\Monitor\Type;

/**
* @author Kevin Bond <[email protected]>
*/
final class MessageTypeMetric
final class MessageTypeMetric extends Metric
{
public readonly Type $type;
private readonly Type $type;

/**
* @param class-string $class
* @param float $averageWaitTime In seconds
* @param float $averageHandlingTime In seconds
*/
public function __construct(
string $class,
public readonly int $totalCount,
public readonly int $failureCount,
public readonly float $averageWaitTime,
public readonly float $averageHandlingTime,
private readonly int $totalCount,
private readonly int $failureCount,
private readonly int $averageWaitTime,
private readonly int $averageHandlingTime,
private readonly int $totalSeconds,
) {
$this->type = new Type($class);
}

public function failRate(): float
public function type(): Type
{
try {
return $this->failureCount / $this->totalCount;
} catch (\DivisionByZeroError) {
return 0;
}
return $this->type;
}

/**
* @param positive-int $divisor Seconds
*/
public function handledPer(int $divisor): float
public function averageWaitTime(): int
{
$interval = $this->totalSeconds / $divisor;
return $this->averageWaitTime;
}

return $this->totalCount / $interval;
public function averageHandlingTime(): int
{
return $this->averageHandlingTime;
}

public function handledPerMinute(): float
public function failureCount(): int
{
return $this->handledPer(60);
return $this->failureCount;
}

public function handledPerHour(): float
public function totalCount(): int
{
return $this->handledPer(60 * 60);
return $this->totalCount;
}

public function handledPerDay(): float
protected function totalSeconds(): int
{
return $this->handledPer(60 * 60 * 24);
return $this->totalSeconds;
}
}
16 changes: 8 additions & 8 deletions src/History/Model/ProcessedMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,25 +146,25 @@ final public function isFailure(): bool
}

/**
* @return float In seconds
* @return int milliseconds
*/
final public function timeInQueue(): float
final public function timeInQueue(): int
{
return $this->waitTime / 1000;
return $this->waitTime;
}

/**
* @return float In seconds
* @return int milliseconds
*/
final public function timeToHandle(): float
final public function timeToHandle(): int
{
return $this->handleTime / 1000;
return $this->handleTime;
}

/**
* @return float In seconds
* @return int milliseconds
*/
final public function timeToProcess(): float
final public function timeToProcess(): int
{
return $this->timeInQueue() + $this->timeToHandle();
}
Expand Down
62 changes: 7 additions & 55 deletions src/History/Snapshot.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
/**
* @author Kevin Bond <[email protected]>
*/
final class Snapshot
final class Snapshot extends Metric
{
private int $successCount;
private int $failureCount;
private float $averageWaitTime;
private float $averageHandlingTime;
private int $averageWaitTime;
private int $averageHandlingTime;
private int $totalSeconds;

public function __construct(private Storage $storage, private Specification $specification)
Expand Down Expand Up @@ -68,62 +68,14 @@ public function failureCount(): int
return $this->failureCount ??= $this->storage->count($this->specification->failures());
}

public function failRate(): float
public function averageWaitTime(): int
{
try {
return $this->failureCount() / $this->totalCount();
} catch (\DivisionByZeroError) {
return 0;
}
}

/**
* @return float In seconds
*/
public function averageWaitTime(): float
{
return $this->averageWaitTime ??= $this->storage->averageWaitTime($this->specification) ?? 0.0;
}

/**
* @return float In seconds
*/
public function averageHandlingTime(): float
{
return $this->averageHandlingTime ??= $this->storage->averageHandlingTime($this->specification) ?? 0.0;
}

/**
* @return float In seconds
*/
public function averageProcessingTime(): float
{
return $this->averageWaitTime() + $this->averageHandlingTime();
}

/**
* @param positive-int $divisor Seconds
*/
public function handledPer(int $divisor): float
{
$interval = $this->totalSeconds() / $divisor;

return $this->totalCount() / $interval;
}

public function handledPerMinute(): float
{
return $this->handledPer(60);
}

public function handledPerHour(): float
{
return $this->handledPer(60 * 60);
return $this->averageWaitTime ??= $this->storage->averageWaitTime($this->specification) ?? 0;
}

public function handledPerDay(): float
public function averageHandlingTime(): int
{
return $this->handledPer(60 * 60 * 24);
return $this->averageHandlingTime ??= $this->storage->averageHandlingTime($this->specification) ?? 0;
}

public function totalSeconds(): int
Expand Down
Loading
Loading