Skip to content

Commit b98385f

Browse files
authored
Merge pull request #56 from patchlevel/memory-limit-shorthand
Accept php.ini style memory limits and reject too large values
2 parents de622b4 + 1eadc4d commit b98385f

4 files changed

Lines changed: 32 additions & 9 deletions

File tree

‎docs/getting-started.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,16 @@ stopping always happens *between* iterations, so your job is never interrupted h
3434
All options are optional. Without limits the worker runs until it is stopped
3535
via `$stop()`, `$worker->stop()` or a SIGTERM/SIGINT signal.
3636

37-
| Option | Type | Description |
38-
|---------------|----------|---------------------------------------------------------------------------------------------------------------------------------|
39-
| `runLimit` | `int` | Stop after this number of iterations. |
40-
| `memoryLimit` | `string` | Stop when memory usage exceeds this value, e.g. `128MB`. Supported units: `B`, `KB`, `MB`, `GB` (case-insensitive, 1024-based). |
41-
| `timeLimit` | `int` | Stop after this number of seconds. |
37+
| Option | Type | Description |
38+
|---------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
39+
| `runLimit` | `int` | Stop after this number of iterations. |
40+
| `memoryLimit` | `string` | Stop when memory usage exceeds this value, e.g. `128MB` or `128M`. Supported units: `B`, `K`/`KB`, `M`/`MB`, `G`/`GB` (case-insensitive, 1024-based). |
41+
| `timeLimit` | `int` | Stop after this number of seconds. |
4242

4343
Limits are checked after each iteration. When a limit is exceeded, the worker logs the reason and stops gracefully.
4444

4545
:::warning
46-
An invalid `memoryLimit` string throws a `Patchlevel\Worker\InvalidFormat` exception.
46+
An invalid or too large `memoryLimit` string throws a `Patchlevel\Worker\InvalidFormat` exception.
4747
:::
4848

4949
:::note

‎src/Bytes.php‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Patchlevel\Worker;
66

77
use function array_key_exists;
8+
use function is_int;
89
use function preg_match;
910
use function sprintf;
1011
use function strtoupper;
@@ -13,8 +14,11 @@ final class Bytes
1314
{
1415
private const SIZES = [
1516
'B' => 1,
17+
'K' => 1_024,
1618
'KB' => 1_024,
19+
'M' => 1_048_576,
1720
'MB' => 1_048_576,
21+
'G' => 1_073_741_824,
1822
'GB' => 1_073_741_824,
1923
];
2024

@@ -36,14 +40,20 @@ public static function parseFromString(string $string): self
3640
throw new InvalidFormat($string);
3741
}
3842

39-
$number = (int)$matches[1];
4043
$unit = strtoupper($matches[2] ?? 'B');
4144

4245
if (!array_key_exists($unit, self::SIZES)) {
4346
throw new InvalidFormat($string);
4447
}
4548

46-
return new self($number * self::SIZES[$unit]);
49+
$bytes = $matches[1] * self::SIZES[$unit];
50+
51+
// integer overflow results in a float
52+
if (!is_int($bytes)) {
53+
throw new InvalidFormat($string);
54+
}
55+
56+
return new self($bytes);
4757
}
4858

4959
public function formatted(): string

‎src/InvalidFormat.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ final class InvalidFormat extends InvalidArgumentException
1212
{
1313
public function __construct(string $message)
1414
{
15-
parent::__construct(sprintf('Invalid byte format received (got: "%s"). The format must consist of a number and a unit. The following units are allowed: B, KB, MB, GB', $message));
15+
parent::__construct(sprintf('Invalid byte format received (got: "%s"). The format must consist of a number and a unit. The following units are allowed: B, K, KB, M, MB, G, GB', $message));
1616
}
1717
}

‎tests/Unit/BytesTest.php‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public static function invalidFormatProvider(): Generator
2828
yield ['-5GB'];
2929
yield ['505Foo'];
3030
yield ['50Kb50'];
31+
yield ['50T'];
32+
yield ['50TB'];
33+
yield ['99999999999GB'];
34+
yield ['99999999999999999999'];
3135
}
3236

3337
#[DataProvider('validParseDataProvider')]
@@ -55,6 +59,15 @@ public static function validParseDataProvider(): Generator
5559
yield ['50Gb', 53_687_091_200, '50.0 GiB'];
5660
yield ['50gb', 53_687_091_200, '50.0 GiB'];
5761

62+
yield ['50K', 51_200, '50.0 KiB'];
63+
yield ['50k', 51_200, '50.0 KiB'];
64+
yield ['512M', 536_870_912, '512.0 MiB'];
65+
yield ['512m', 536_870_912, '512.0 MiB'];
66+
yield ['1G', 1_073_741_824, '1.0 GiB'];
67+
yield ['1g', 1_073_741_824, '1.0 GiB'];
68+
69+
yield ['0050MB', 52_428_800, '50.0 MiB'];
70+
5871
yield ['1024b', 1024, '1.0 KiB'];
5972
yield ['1024Kb', 1_048_576, '1.0 MiB'];
6073
yield ['1024Mb', 1_073_741_824, '1.0 GiB'];

0 commit comments

Comments
 (0)