Skip to content

Commit c58851c

Browse files
authored
Merge pull request #34 from dotkernel/tcp-commands
Fixed limit bug and added commands usage to docs
2 parents 844be5a + aa24e75 commit c58851c

File tree

6 files changed

+152
-45
lines changed

6 files changed

+152
-45
lines changed

config/autoload/cli.global.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
'version' => '1.0.0',
1616
'name' => 'DotKernel CLI',
1717
'commands' => [
18-
"swoole:start" => StartCommand::class,
19-
"swoole:stop" => StopCommand::class,
20-
"messenger:start" => ConsumeMessagesCommand::class,
21-
"messenger:debug" => DebugCommand::class,
22-
"messenger:processed" => GetProcessedMessagesCommand::class,
23-
"messenger:failed" => GetFailedMessagesCommand::class,
18+
"swoole:start" => StartCommand::class,
19+
"swoole:stop" => StopCommand::class,
20+
"messenger:start" => ConsumeMessagesCommand::class,
21+
"messenger:debug" => DebugCommand::class,
22+
"processed" => GetProcessedMessagesCommand::class,
23+
"failed" => GetFailedMessagesCommand::class,
2424
],
2525
],
2626
FileLockerInterface::class => [

docs/book/v1/commands.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## Available commands and usage
2+
3+
The commands available are:
4+
5+
1. `GetFailedMessagesCommand.php` - returns logs with messages that failed to process (levelName:error)
6+
2. `GetProcessedMessagesCommand.php` - returns logs with messages that were successfully processed (levelName:info)
7+
8+
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:
9+
10+
### CLI
11+
12+
To run the commands via CLI, use the following syntax:
13+
14+
`php bin/cli.php failed --start="yyyy-mm-dd" --end="yyyy-mm-dd" --limit=int`
15+
16+
`php bin/cli.php processed --start="yyyy-mm-dd" --end="yyyy-mm-dd" --limit=int`
17+
18+
### TCP message
19+
20+
To use commands using TCP messages the following messages can be used:
21+
22+
`echo "failed --start=yyyy-mm-dd --end=yyyy-mm-dd --limit=days" | socat -t1 - TCP:host:port`
23+
24+
`echo "processed --start=yyyy-mm-dd --end=yyyy-mm-dd --limit=days" | socat -t1 - TCP:host:port`
25+
26+
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.
27+
28+
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:
29+
30+
`echo "control" | socat -t1 - TCP:host:port`
31+
32+
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.

src/App/Message/ExampleMessageHandler.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,18 @@ public function __construct(
2626

2727
public function __invoke(ExampleMessage $message): void
2828
{
29+
$payload = $message->getPayload();
30+
2931
try {
3032
// Throwing an exception to satisfy PHPStan (replace with own code)
31-
throw new \Exception("Failed to execute");
33+
// For proof of concept and testing purposes message "control" will automatically mark it as successfully
34+
// processed and logged as info
35+
if ($payload['foo'] === 'control') {
36+
$this->logger->info($payload['foo'] . ': was processed successfully');
37+
} else {
38+
throw new \Exception("Failed to execute");
39+
}
3240
} catch (\Throwable $exception) {
33-
$payload = $message->getPayload();
3441
$this->logger->error($payload['foo'] . ' failed with message: '
3542
. $exception->getMessage() . ' after ' . ($payload['retry'] ?? 0) . ' retries');
3643
$this->retry($payload);

src/Swoole/Command/GetFailedMessagesCommand.php

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
use Symfony\Component\Console\Input\InputOption;
1212
use Symfony\Component\Console\Output\OutputInterface;
1313

14-
use function date;
14+
use function dirname;
1515
use function file;
16+
use function file_exists;
1617
use function is_numeric;
1718
use function json_decode;
18-
use function preg_match;
1919
use function strtolower;
2020
use function strtotime;
2121

@@ -46,27 +46,56 @@ protected function configure(): void
4646

4747
protected function execute(InputInterface $input, OutputInterface $output): int
4848
{
49-
$start = $input->getOption('start');
50-
$end = $input->getOption('end');
51-
$limit = $input->getOption('limit');
52-
53-
if (! $end) {
54-
$end = date('Y-m-d H:i:s');
55-
} elseif (! preg_match('/\d{2}:\d{2}:\d{2}/', $end)) {
56-
$end .= ' 23:59:59';
49+
try {
50+
$startOption = $input->getOption('start');
51+
$endOption = $input->getOption('end');
52+
$limit = $input->getOption('limit');
53+
54+
$startDate = $startOption ? new \DateTimeImmutable($startOption) : null;
55+
$endDate = $endOption ? new \DateTimeImmutable($endOption) : null;
56+
} catch (\Exception $e) {
57+
$output->writeln('<error>Invalid date format provided.</error>');
58+
return Command::FAILURE;
5759
}
5860

59-
if ($limit && is_numeric($limit) && ! $start) {
60-
$start = date('Y-m-d H:i:s', strtotime("-{$limit} days", strtotime($end)));
61-
} elseif ($start && ! preg_match('/\d{2}:\d{2}:\d{2}/', $start)) {
62-
$start .= ' 00:00:00';
61+
if ($startDate && $startDate->format('H:i:s') === '00:00:00') {
62+
$startDate = $startDate->setTime(0, 0, 0);
6363
}
6464

65-
$startTimestamp = $start ? strtotime($start) : null;
66-
$endTimestamp = $end ? strtotime($end) : null;
65+
if ($endDate && $endDate->format('H:i:s') === '00:00:00') {
66+
$endDate = $endDate->setTime(23, 59, 59);
67+
}
68+
69+
if ($limit && is_numeric($limit)) {
70+
if ($startDate && ! $endDate) {
71+
$endDate = $startDate->modify("+{$limit} days");
72+
} elseif (! $startDate && $endDate) {
73+
$startDate = $endDate->modify("-{$limit} days");
74+
}
75+
}
76+
77+
if (! $endDate) {
78+
$endDate = new \DateTime();
79+
}
80+
81+
if ($startDate > $endDate) {
82+
$output->writeln('<error>The start date cannot be after the end date.</error>');
83+
return Command::FAILURE;
84+
}
6785

68-
$logPath = 'log/queue-log.log';
69-
$lines = file($logPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
86+
$logPath = dirname(__DIR__, 3) . '/log/queue-log.log';
87+
88+
if (! file_exists($logPath)) {
89+
$output->writeln("<error>Log file not found: $logPath</error>");
90+
return Command::FAILURE;
91+
}
92+
93+
$lines = file($logPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
94+
95+
$startTimestamp = $startDate?->getTimestamp();
96+
$endTimestamp = $endDate->getTimestamp();
97+
98+
$found = false;
7099

71100
foreach ($lines as $line) {
72101
$entry = json_decode($line, true);
@@ -88,6 +117,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
88117
}
89118

90119
$output->writeln($line);
120+
$found = true;
121+
}
122+
123+
if (! $found) {
124+
$output->writeln('<comment>No matching log entries found.</comment>');
91125
}
92126

93127
return Command::SUCCESS;

src/Swoole/Command/GetProcessedMessagesCommand.php

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
use Symfony\Component\Console\Input\InputOption;
1212
use Symfony\Component\Console\Output\OutputInterface;
1313

14-
use function date;
14+
use function dirname;
1515
use function file;
16+
use function file_exists;
1617
use function is_numeric;
1718
use function json_decode;
18-
use function preg_match;
1919
use function strtolower;
2020
use function strtotime;
2121

@@ -46,27 +46,56 @@ protected function configure(): void
4646

4747
protected function execute(InputInterface $input, OutputInterface $output): int
4848
{
49-
$start = $input->getOption('start');
50-
$end = $input->getOption('end');
51-
$limit = $input->getOption('limit');
52-
53-
if (! $end) {
54-
$end = date('Y-m-d H:i:s');
55-
} elseif (! preg_match('/\d{2}:\d{2}:\d{2}/', $end)) {
56-
$end .= ' 23:59:59';
49+
try {
50+
$startOption = $input->getOption('start');
51+
$endOption = $input->getOption('end');
52+
$limit = $input->getOption('limit');
53+
54+
$startDate = $startOption ? new \DateTimeImmutable($startOption) : null;
55+
$endDate = $endOption ? new \DateTimeImmutable($endOption) : null;
56+
} catch (\Exception $e) {
57+
$output->writeln('<error>Invalid date format provided.</error>');
58+
return Command::FAILURE;
5759
}
5860

59-
if ($limit && is_numeric($limit) && ! $start) {
60-
$start = date('Y-m-d H:i:s', strtotime("-{$limit} days", strtotime($end)));
61-
} elseif ($start && ! preg_match('/\d{2}:\d{2}:\d{2}/', $start)) {
62-
$start .= ' 00:00:00';
61+
if ($startDate && $startDate->format('H:i:s') === '00:00:00') {
62+
$startDate = $startDate->setTime(0, 0, 0);
6363
}
6464

65-
$startTimestamp = $start ? strtotime($start) : null;
66-
$endTimestamp = $end ? strtotime($end) : null;
65+
if ($endDate && $endDate->format('H:i:s') === '00:00:00') {
66+
$endDate = $endDate->setTime(23, 59, 59);
67+
}
68+
69+
if ($limit && is_numeric($limit)) {
70+
if ($startDate && ! $endDate) {
71+
$endDate = $startDate->modify("+{$limit} days");
72+
} elseif (! $startDate && $endDate) {
73+
$startDate = $endDate->modify("-{$limit} days");
74+
}
75+
}
76+
77+
if (! $endDate) {
78+
$endDate = new \DateTime();
79+
}
80+
81+
if ($startDate > $endDate) {
82+
$output->writeln('<error>The start date cannot be after the end date.</error>');
83+
return Command::FAILURE;
84+
}
6785

68-
$logPath = 'log/queue-log.log';
69-
$lines = file($logPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
86+
$logPath = dirname(__DIR__, 3) . '/log/queue-log.log';
87+
88+
if (! file_exists($logPath)) {
89+
$output->writeln("<error>Log file not found: $logPath</error>");
90+
return Command::FAILURE;
91+
}
92+
93+
$lines = file($logPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
94+
95+
$startTimestamp = $startDate?->getTimestamp();
96+
$endTimestamp = $endDate->getTimestamp();
97+
98+
$found = false;
7099

71100
foreach ($lines as $line) {
72101
$entry = json_decode($line, true);
@@ -88,6 +117,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
88117
}
89118

90119
$output->writeln($line);
120+
$found = true;
121+
}
122+
123+
if (! $found) {
124+
$output->writeln('<comment>No matching log entries found.</comment>');
91125
}
92126

93127
return Command::SUCCESS;

src/Swoole/Delegators/TCPServerDelegator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function __invoke(ContainerInterface $container, string $serviceName, cal
7777
$logger->error("Error running command: " . $e->getMessage());
7878
}
7979
} else {
80-
$bus->dispatch(new ExampleMessage(["foo" => $data]));
80+
$bus->dispatch(new ExampleMessage(["foo" => $message]));
8181
$bus->dispatch(new ExampleMessage(["foo" => "with 5 seconds delay"]), [
8282
new DelayStamp(5000),
8383
]);

0 commit comments

Comments
 (0)