diff --git a/config/autoload/cli.global.php b/config/autoload/cli.global.php
index 29b0bd0..f9b2d68 100644
--- a/config/autoload/cli.global.php
+++ b/config/autoload/cli.global.php
@@ -15,12 +15,12 @@
'version' => '1.0.0',
'name' => 'DotKernel CLI',
'commands' => [
- "swoole:start" => StartCommand::class,
- "swoole:stop" => StopCommand::class,
- "messenger:start" => ConsumeMessagesCommand::class,
- "messenger:debug" => DebugCommand::class,
- "messenger:processed" => GetProcessedMessagesCommand::class,
- "messenger:failed" => GetFailedMessagesCommand::class,
+ "swoole:start" => StartCommand::class,
+ "swoole:stop" => StopCommand::class,
+ "messenger:start" => ConsumeMessagesCommand::class,
+ "messenger:debug" => DebugCommand::class,
+ "processed" => GetProcessedMessagesCommand::class,
+ "failed" => GetFailedMessagesCommand::class,
],
],
FileLockerInterface::class => [
diff --git a/docs/book/v1/commands.md b/docs/book/v1/commands.md
new file mode 100644
index 0000000..f0faaf5
--- /dev/null
+++ b/docs/book/v1/commands.md
@@ -0,0 +1,32 @@
+## Available commands and usage
+
+The commands available are:
+
+1. `GetFailedMessagesCommand.php` - returns logs with messages that failed to process (levelName:error)
+2. `GetProcessedMessagesCommand.php` - returns logs with messages that were successfully processed (levelName:info)
+
+Both commands are used to extract data that can be filtered by period from the log file. The commands can be run in two different ways:
+
+### CLI
+
+To run the commands via CLI, use the following syntax:
+
+`php bin/cli.php failed --start="yyyy-mm-dd" --end="yyyy-mm-dd" --limit=int`
+
+`php bin/cli.php processed --start="yyyy-mm-dd" --end="yyyy-mm-dd" --limit=int`
+
+### TCP message
+
+To use commands using TCP messages the following messages can be used:
+
+`echo "failed --start=yyyy-mm-dd --end=yyyy-mm-dd --limit=days" | socat -t1 - TCP:host:port`
+
+`echo "processed --start=yyyy-mm-dd --end=yyyy-mm-dd --limit=days" | socat -t1 - TCP:host:port`
+
+In both cases the flags are optional. Keep in mind if both `start` and `end` are set, `limit` will not be applied, it's only used when one of `start` or `end` is missing.
+
+In order to be able to test the `processed` command, by default when processing the "control" message, it is logged as successfully processed with `"levelName":"info"` simulating that the message was processed successfully. To use it run the following message:
+
+`echo "control" | socat -t1 - TCP:host:port`
+
+Using `-t1` flag is not necessary but can be useful, it is used to set a timeout of n seconds for both reading and writing, after n second of inactivity, socat will terminate the connection. If the timeout is not set and the server does not respond or keep the connection open, the socat process could hang indefinitely.
diff --git a/src/App/Message/ExampleMessageHandler.php b/src/App/Message/ExampleMessageHandler.php
index 2d7ddf6..63bf30a 100644
--- a/src/App/Message/ExampleMessageHandler.php
+++ b/src/App/Message/ExampleMessageHandler.php
@@ -26,11 +26,18 @@ public function __construct(
public function __invoke(ExampleMessage $message): void
{
+ $payload = $message->getPayload();
+
try {
// Throwing an exception to satisfy PHPStan (replace with own code)
- throw new \Exception("Failed to execute");
+ // For proof of concept and testing purposes message "control" will automatically mark it as successfully
+ // processed and logged as info
+ if ($payload['foo'] === 'control') {
+ $this->logger->info($payload['foo'] . ': was processed successfully');
+ } else {
+ throw new \Exception("Failed to execute");
+ }
} catch (\Throwable $exception) {
- $payload = $message->getPayload();
$this->logger->error($payload['foo'] . ' failed with message: '
. $exception->getMessage() . ' after ' . ($payload['retry'] ?? 0) . ' retries');
$this->retry($payload);
diff --git a/src/Swoole/Command/GetFailedMessagesCommand.php b/src/Swoole/Command/GetFailedMessagesCommand.php
index afbc893..21fab0a 100644
--- a/src/Swoole/Command/GetFailedMessagesCommand.php
+++ b/src/Swoole/Command/GetFailedMessagesCommand.php
@@ -11,11 +11,11 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-use function date;
+use function dirname;
use function file;
+use function file_exists;
use function is_numeric;
use function json_decode;
-use function preg_match;
use function strtolower;
use function strtotime;
@@ -46,27 +46,56 @@ protected function configure(): void
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $start = $input->getOption('start');
- $end = $input->getOption('end');
- $limit = $input->getOption('limit');
-
- if (! $end) {
- $end = date('Y-m-d H:i:s');
- } elseif (! preg_match('/\d{2}:\d{2}:\d{2}/', $end)) {
- $end .= ' 23:59:59';
+ try {
+ $startOption = $input->getOption('start');
+ $endOption = $input->getOption('end');
+ $limit = $input->getOption('limit');
+
+ $startDate = $startOption ? new \DateTimeImmutable($startOption) : null;
+ $endDate = $endOption ? new \DateTimeImmutable($endOption) : null;
+ } catch (\Exception $e) {
+ $output->writeln('Invalid date format provided.');
+ return Command::FAILURE;
}
- if ($limit && is_numeric($limit) && ! $start) {
- $start = date('Y-m-d H:i:s', strtotime("-{$limit} days", strtotime($end)));
- } elseif ($start && ! preg_match('/\d{2}:\d{2}:\d{2}/', $start)) {
- $start .= ' 00:00:00';
+ if ($startDate && $startDate->format('H:i:s') === '00:00:00') {
+ $startDate = $startDate->setTime(0, 0, 0);
}
- $startTimestamp = $start ? strtotime($start) : null;
- $endTimestamp = $end ? strtotime($end) : null;
+ if ($endDate && $endDate->format('H:i:s') === '00:00:00') {
+ $endDate = $endDate->setTime(23, 59, 59);
+ }
+
+ if ($limit && is_numeric($limit)) {
+ if ($startDate && ! $endDate) {
+ $endDate = $startDate->modify("+{$limit} days");
+ } elseif (! $startDate && $endDate) {
+ $startDate = $endDate->modify("-{$limit} days");
+ }
+ }
+
+ if (! $endDate) {
+ $endDate = new \DateTime();
+ }
+
+ if ($startDate > $endDate) {
+ $output->writeln('The start date cannot be after the end date.');
+ return Command::FAILURE;
+ }
- $logPath = 'log/queue-log.log';
- $lines = file($logPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ $logPath = dirname(__DIR__, 3) . '/log/queue-log.log';
+
+ if (! file_exists($logPath)) {
+ $output->writeln("Log file not found: $logPath");
+ return Command::FAILURE;
+ }
+
+ $lines = file($logPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+
+ $startTimestamp = $startDate?->getTimestamp();
+ $endTimestamp = $endDate->getTimestamp();
+
+ $found = false;
foreach ($lines as $line) {
$entry = json_decode($line, true);
@@ -88,6 +117,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$output->writeln($line);
+ $found = true;
+ }
+
+ if (! $found) {
+ $output->writeln('No matching log entries found.');
}
return Command::SUCCESS;
diff --git a/src/Swoole/Command/GetProcessedMessagesCommand.php b/src/Swoole/Command/GetProcessedMessagesCommand.php
index 0c559bf..9732c66 100644
--- a/src/Swoole/Command/GetProcessedMessagesCommand.php
+++ b/src/Swoole/Command/GetProcessedMessagesCommand.php
@@ -11,11 +11,11 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-use function date;
+use function dirname;
use function file;
+use function file_exists;
use function is_numeric;
use function json_decode;
-use function preg_match;
use function strtolower;
use function strtotime;
@@ -46,27 +46,56 @@ protected function configure(): void
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $start = $input->getOption('start');
- $end = $input->getOption('end');
- $limit = $input->getOption('limit');
-
- if (! $end) {
- $end = date('Y-m-d H:i:s');
- } elseif (! preg_match('/\d{2}:\d{2}:\d{2}/', $end)) {
- $end .= ' 23:59:59';
+ try {
+ $startOption = $input->getOption('start');
+ $endOption = $input->getOption('end');
+ $limit = $input->getOption('limit');
+
+ $startDate = $startOption ? new \DateTimeImmutable($startOption) : null;
+ $endDate = $endOption ? new \DateTimeImmutable($endOption) : null;
+ } catch (\Exception $e) {
+ $output->writeln('Invalid date format provided.');
+ return Command::FAILURE;
}
- if ($limit && is_numeric($limit) && ! $start) {
- $start = date('Y-m-d H:i:s', strtotime("-{$limit} days", strtotime($end)));
- } elseif ($start && ! preg_match('/\d{2}:\d{2}:\d{2}/', $start)) {
- $start .= ' 00:00:00';
+ if ($startDate && $startDate->format('H:i:s') === '00:00:00') {
+ $startDate = $startDate->setTime(0, 0, 0);
}
- $startTimestamp = $start ? strtotime($start) : null;
- $endTimestamp = $end ? strtotime($end) : null;
+ if ($endDate && $endDate->format('H:i:s') === '00:00:00') {
+ $endDate = $endDate->setTime(23, 59, 59);
+ }
+
+ if ($limit && is_numeric($limit)) {
+ if ($startDate && ! $endDate) {
+ $endDate = $startDate->modify("+{$limit} days");
+ } elseif (! $startDate && $endDate) {
+ $startDate = $endDate->modify("-{$limit} days");
+ }
+ }
+
+ if (! $endDate) {
+ $endDate = new \DateTime();
+ }
+
+ if ($startDate > $endDate) {
+ $output->writeln('The start date cannot be after the end date.');
+ return Command::FAILURE;
+ }
- $logPath = 'log/queue-log.log';
- $lines = file($logPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ $logPath = dirname(__DIR__, 3) . '/log/queue-log.log';
+
+ if (! file_exists($logPath)) {
+ $output->writeln("Log file not found: $logPath");
+ return Command::FAILURE;
+ }
+
+ $lines = file($logPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+
+ $startTimestamp = $startDate?->getTimestamp();
+ $endTimestamp = $endDate->getTimestamp();
+
+ $found = false;
foreach ($lines as $line) {
$entry = json_decode($line, true);
@@ -88,6 +117,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$output->writeln($line);
+ $found = true;
+ }
+
+ if (! $found) {
+ $output->writeln('No matching log entries found.');
}
return Command::SUCCESS;
diff --git a/src/Swoole/Delegators/TCPServerDelegator.php b/src/Swoole/Delegators/TCPServerDelegator.php
index 0953a97..bd9145a 100644
--- a/src/Swoole/Delegators/TCPServerDelegator.php
+++ b/src/Swoole/Delegators/TCPServerDelegator.php
@@ -77,7 +77,7 @@ public function __invoke(ContainerInterface $container, string $serviceName, cal
$logger->error("Error running command: " . $e->getMessage());
}
} else {
- $bus->dispatch(new ExampleMessage(["foo" => $data]));
+ $bus->dispatch(new ExampleMessage(["foo" => $message]));
$bus->dispatch(new ExampleMessage(["foo" => "with 5 seconds delay"]), [
new DelayStamp(5000),
]);