Skip to content

Commit

Permalink
Report Scheduled Task outputs to Appkeep (#23)
Browse files Browse the repository at this point in the history
* fix memory check

* update version

* add new event to report cronjob outputs

* don't report appkeep:run output

* add start at/finish at timestamps

* refactor

* fixes

* update guzzle version

* fix guzzle
  • Loading branch information
aozisik authored May 22, 2023
1 parent 05c67e9 commit 09e0883
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 13 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ jobs:
- name: Install dependencies
run: |
composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
if [ "${{ matrix.laravel }}" = "7.*" ]; then composer require "guzzlehttp/guzzle:7.6.*" --no-interaction --no-update; fi
composer update --${{ matrix.stability }} --prefer-dist --no-interaction
- name: Execute tests
run: vendor/bin/phpunit
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
],
"require": {
"php": "^7.4|^8.0",
"guzzlehttp/guzzle": "^6.3|^7.0",
"guzzlehttp/guzzle": "^6.3.1|^7.0",
"illuminate/console": "^7.0|^8.0|^9.0|^10.0",
"illuminate/support": "^7.0|^8.0|^9.0|^10.0"
},
Expand Down Expand Up @@ -58,4 +58,4 @@
}
}
}
}
}
27 changes: 26 additions & 1 deletion src/AppkeepProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Support\ServiceProvider;
use Appkeep\Laravel\Commands\RunCommand;
use Illuminate\Console\Scheduling\Event;
use Appkeep\Laravel\Commands\InitCommand;
use Appkeep\Laravel\Commands\ListCommand;
use Appkeep\Laravel\Commands\LoginCommand;
Expand Down Expand Up @@ -66,7 +67,31 @@ public function bootForConsole()

$schedule->command('appkeep:run')
->everyMinute()
->runInBackground();
->runInBackground()
->evenInMaintenanceMode();

collect($schedule->events())
->filter(function ($event) {
return $event->command && ! str_contains($event->command, 'appkeep:run');
})
->each(function (Event $event) {
/**
* @var AppkeepService
*/
$appkeep = app('appkeep');

$event->before(
fn () => $appkeep->scheduledTaskStarted($event)
);

$event->onFailureWithOutput(
fn ($output) => $appkeep->scheduledTaskFailed($event, $output)
);

$event->onSuccessWithOutput(
fn ($output) => $appkeep->scheduledTaskCompleted($event, $output)
);
});
});
}
}
5 changes: 4 additions & 1 deletion src/AppkeepService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
namespace Appkeep\Laravel;

use InvalidArgumentException;
use Appkeep\Laravel\Concerns\ReportsScheduledTaskOutputs;

class AppkeepService
{
use ReportsScheduledTaskOutputs;

public $checks = [];

public function version()
{
return '0.5.0';
return '0.6.0';
}

public function client()
Expand Down
64 changes: 64 additions & 0 deletions src/Concerns/ReportsScheduledTaskOutputs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace Appkeep\Laravel\Concerns;

use Appkeep\Laravel\ScheduledTaskOutput;
use Illuminate\Console\Scheduling\Event;

trait ReportsScheduledTaskOutputs
{
private $scheduledTaskStartMs;
private $scheduledTaskStartedAt;

public function scheduledTaskStarted(Event $task)
{
$this->scheduledTaskStartMs = hrtime(true);
$this->scheduledTaskStartedAt = now();
}

/**
* Get the duration of the scheduled task run in milliseconds
*/
private function getScheduledTaskRunDuration(): int
{
return round((hrtime(true) - $this->scheduledTaskStartMs) / 1e+6);
}

public function scheduledTaskFailed(Event $task, $output)
{
$duration = $this->getScheduledTaskRunDuration();
$finishedAt = now();

$output = ScheduledTaskOutput::fromScheduledTask($task)
->failed()
->setDuration($duration)
->setStartedAt($this->scheduledTaskStartedAt)
->setFinishedAt($finishedAt)
->setOutput($output);

try {
$this->client()->sendScheduledTaskOutput($output);
} catch (\Exception $e) {
report($e);
}
}

public function scheduledTaskCompleted(Event $task, $output)
{
$duration = $this->getScheduledTaskRunDuration();
$finishedAt = now();

$output = ScheduledTaskOutput::fromScheduledTask($task)
->succeeded()
->setDuration($duration)
->setStartedAt($this->scheduledTaskStartedAt)
->setFinishedAt($finishedAt)
->setOutput($output);

try {
$this->client()->sendScheduledTaskOutput($output);
} catch (\Exception $e) {
report($e);
}
}
}
5 changes: 3 additions & 2 deletions src/Contexts/SpecsContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ private function totalDiskspace()
private function totalMemory()
{
if (PHP_OS === 'Linux') {
$output = shell_exec('free -g | grep Mem | awk \'{print $2}\'');
$output = shell_exec('free -m | grep Mem | awk \'{print $2}\'');
$output = $output / 1024; // convert MB to GB
} elseif (PHP_OS === 'Darwin' || PHP_OS === 'FreeBSD') {
$output = shell_exec('sysctl -n hw.memsize');
$output = $output / 1073741824; // convert bytes to GB
} else {
throw new RuntimeException('Operating system not supported!');
}

return (int) trim($output);
return (int) round(trim($output));
}
}
8 changes: 4 additions & 4 deletions src/Events/PostDeployEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Appkeep\Laravel\Contexts\GitContext;
use Appkeep\Laravel\Contexts\SpecsContext;
use Illuminate\Console\Scheduling\Schedule;
use Appkeep\Laravel\Support\ScheduledEventId;
use Appkeep\Laravel\Support\ScheduledTaskId;

/**
* This event sends data that changes with every deployment to Appkeep.
Expand Down Expand Up @@ -48,14 +48,14 @@ private function getScheduledTasks()
// We can't track scheduled events without a signature (callbacks)
// We also don't want to track scheduled events that won't fire off in this environment anyway.
->filter(function ($event) {
return $event->command && empty($event->environments) || in_array(
return $event->command && (empty($event->environments) || in_array(
app()->environment(),
$event->environments
);
));
})
->map(function ($event) {
return [
'id' => ScheduledEventId::get($event),
'id' => ScheduledTaskId::get($event),
'command' => $event->command,
'description' => $event->description,
'expression' => $event->expression,
Expand Down
32 changes: 32 additions & 0 deletions src/Events/ScheduledTaskEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Appkeep\Laravel\Events;

use Appkeep\Laravel\ScheduledTaskOutput;

class ScheduledTaskEvent extends AbstractEvent
{
protected $name = 'scheduled-task';

public function __construct(private ScheduledTaskOutput $output)
{
parent::__construct();
}

public function toArray()
{
return array_merge(
parent::toArray(),
[
'output' => [
'id' => $this->output->id,
'success' => $this->output->success,
'duration' => $this->output->duration,
'output' => $this->output->output,
'started_at' => $this->output->startedAt,
'finished_at' => $this->output->finishedAt,
],
]
);
}
}
11 changes: 10 additions & 1 deletion src/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Appkeep\Laravel\Facades\Appkeep;
use Illuminate\Support\Facades\Http;
use Appkeep\Laravel\Events\AbstractEvent;
use Appkeep\Laravel\Events\ScheduledTaskEvent;

class HttpClient
{
Expand All @@ -23,12 +24,20 @@ public function __construct($key)
*/
public function sendEvent(AbstractEvent $event)
{
return Http::withoutVerifying()->withHeaders($this->defaultHeaders())->post(
return Http::withHeaders($this->defaultHeaders())->post(
config('appkeep.endpoint'),
$event->toArray()
);
}

/**
* Send scheduled task result
*/
public function sendScheduledTaskOutput(ScheduledTaskOutput $output)
{
return $this->sendEvent(new ScheduledTaskEvent($output))->throw();
}

protected function defaultHeaders()
{
return [
Expand Down
69 changes: 69 additions & 0 deletions src/ScheduledTaskOutput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Appkeep\Laravel;

use DateTime;
use Illuminate\Console\Scheduling\Event;
use Appkeep\Laravel\Support\ScheduledTaskId;

class ScheduledTaskOutput
{
public bool $success = true;
public ?float $duration = null;
public ?string $output = null;
public ?DateTime $startedAt = null;
public ?DateTime $finishedAt = null;

public function __construct(public string $id)
{
}

public static function fromScheduledTask(Event $task)
{
return new self(
ScheduledTaskId::get($task)
);
}

public function succeeded()
{
$this->success = true;

return $this;
}

public function failed()
{
$this->success = false;

return $this;
}

public function setDuration(float $duration)
{
$this->duration = $duration;

return $this;
}

public function setOutput(string $output)
{
$this->output = $output;

return $this;
}

public function setStartedAt(DateTime $startedAt)
{
$this->startedAt = $startedAt;

return $this;
}

public function setFinishedAt(DateTime $finishedAt)
{
$this->finishedAt = $finishedAt;

return $this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
* Allows us to get a ID for a scheduled event.
* This way we can match up pings from events to records on Appkeep server.
*/
class ScheduledEventId
class ScheduledTaskId
{
public static function get(Event $event)
{
return hash('md5', $event->command . '-' . $event->expression);
return hash('md5', 'laravel-' . $event->command . '-' . $event->expression);
}
}

0 comments on commit 09e0883

Please sign in to comment.