Skip to content

Commit

Permalink
feat: Clean up, custom cache hit ratio check and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Ware committed Dec 12, 2023
1 parent 0b0763f commit 8a17a66
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 22 deletions.
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,67 @@ composer require chris-ware/pulse-health-check

## Usage

TBD
### Cache Hit Ratio Check

This check will warn or fail if the cache hit ratio hits a certain percentage threshold. By default, it will fail at 10% hit ratio and warn at 25%.

```php
use ChrisWare\PulseHealthCheck\Checks\PulseCacheHitRatioCheck;

PulseCacheHitRatioCheck::new();
```

Configure the failure and warning levels:

```php
use ChrisWare\PulseHealthCheck\Checks\PulseCacheHitRatioCheck;

PulseCacheHitRatioCheck::new()->failWhenSizeRatioBelow(25)->warnWhenSizeRatioBelow(50);
```
### Generic Check

This generic check will accommodate most basic circumstances for Pulse aggregates. Every check must have a defined `for` method on it for it to understand which aggregate type to use.

Example for slow query aggregation:

```php
use ChrisWare\PulseHealthCheck\Checks\PulseCheck;

PulseCheck::new()
->for('slow_query')
->failWhenAbove(5)
->warnWhenAbove(3)
->interval(\Carbon\CarbonInterval::minutes(5));
```

Example for user request aggregation:

```php
use ChrisWare\PulseHealthCheck\Checks\PulseCheck;

PulseCheck::new()
->for('user_request')
->aggregate('count')
->failWhenAbove(500)
->warnWhenAbove(300)
->interval(\Carbon\CarbonInterval::minutes(5));
```

#### Available methods

**for**: Determine the aggregation type to use

**aggregate**: Determine the aggregation value to use (defaults to `max`)

**failWhenAbove**: Set the value to fail if greater than or equal to

**failWhenBelow**: Set the value to fail if less than or equal to

**warnWhenAbove**: Set the value to warn if greater than or equal to

**warnWhenBelow**: Set the value to warn if less than or equal to

**interval**: The CarbonInterval for aggregations to be evaluated (defaults to 1 hour)

## Testing

Expand Down
61 changes: 61 additions & 0 deletions src/Checks/PulseCacheHitRatioCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace ChrisWare\PulseHealthCheck\Checks;

use Carbon\CarbonInterval;
use Laravel\Pulse\Facades\Pulse;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;

class PulseCacheHitRatioCheck extends Check
{
protected float $warnWhenRatioBelow = 25;
protected float $failWhenRatioBelow = 10;

protected CarbonInterval $interval;

public function failWhenSizeRatioBelow(float $failPercentage): self
{
$this->failWhenRatioBelow = $failPercentage;

return $this;
}

public function warnWhenSizeRatioBelow(float $warnPercentage): self
{
$this->warnWhenRatioBelow = $warnPercentage;

return $this;
}

public function interval(CarbonInterval $interval): static
{
$this->interval = $interval;

return $this;
}

public function run(): Result
{
$cacheHits = Pulse::aggregateTypes(['cache_hit', 'cache_miss'], 'count', $this->interval ?? CarbonInterval::hour())
->map(function ($row) {
return (object) [
'key' => $row->key,
'hits' => $row->cache_hit ?? 0,
'misses' => $row->cache_miss ?? 0,
'ratio' => ((int) ($row->cache_hit / ($row->cache_hit + $row->cache_miss) * 10000)) / 100,
];
});
$failRatio = $cacheHits->filter(fn ($row) => $row->ratio <= $this->failWhenRatioBelow);
if ($failRatio->isNotEmpty()) {
return Result::make()->failed("{$failRatio->count()} item(s) below {$this->failWhenRatioBelow}%");
}

$warnRatio = $cacheHits->filter(fn ($row) => $row->ratio < $this->warnWhenRatioBelow);
if ($warnRatio->isNotEmpty()) {
return Result::make()->warning("{$warnRatio->count()} item(s) below {$this->warnWhenRatioBelow}%");
}

return Result::make();
}
}
44 changes: 23 additions & 21 deletions src/Checks/PulseCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@

class PulseCheck extends Check
{
protected string $field;
protected string $aggregate = 'max';

protected bool $inverted = false;

protected string $type;

protected int $warningLevel = 1000;
protected float $warningLevel;

protected int $failureLevel = 500;
protected float $failureLevel;

protected CarbonInterval $interval;

Expand All @@ -31,64 +31,66 @@ public function for(string $type): static
return $this;
}

public function failureLevel(int $max): static
public function failWhenAbove(float $level): static
{
$this->failureLevel = $max;
$this->failureLevel = $level;
$this->inverted = false;

return $this;
}

public function warningLevel(int $max): static
public function failWhenBelow(float $level): static
{
$this->warningLevel = $max;
$this->failureLevel = $level;
$this->inverted = true;

return $this;
}

public function interval(CarbonInterval $interval): static
public function warnWhenAbove(float $level): static
{
$this->interval = $interval;
$this->warningLevel = $level;
$this->inverted = false;

return $this;
}

public function byMax(): static
public function warnWhenBelow(float $level): static
{
$this->field = 'max';
$this->warningLevel = $level;
$this->inverted = true;

return $this;
}

public function byCount(): static
public function interval(CarbonInterval $interval): static
{
$this->field = 'count';
$this->interval = $interval;

return $this;
}

public function inverted(): static
public function aggregate(string $aggregate): static
{
$this->inverted = true;
$this->aggregate = $aggregate;

return $this;
}

public function run(): Result
{
$this->interval ??= CarbonInterval::hours(24);

$this->field ??= 'max';
$this->interval ??= CarbonInterval::hour();

$value = Pulse::aggregate($this->type, $this->field, $this->interval, $this->field)->first()?->{$this->field} ?? 0;
$value = Pulse::aggregate($this->type, $this->aggregate, $this->interval, $this->aggregate)->first()?->{$this->aggregate} ?? 0;
$value = Number::format($value);

$result = Result::make()->check($this);

if ($value >= $this->failureLevel || ($this->inverted && ($value <= $this->failureLevel))) {
if ((!$this->inverted && $value >= $this->failureLevel) || ($this->inverted && $value <= $this->failureLevel)) {
return $result->failed("{$value}");
}

if ($value >= $this->warningLevel || ($this->inverted && ($value <= $this->warningLevel))) {
if ((!$this->inverted && $value >= $this->warningLevel) || ($this->inverted && $value <= $this->warningLevel)) {
return $result->warning("{$value}");
}

Expand Down

0 comments on commit 8a17a66

Please sign in to comment.