Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5682652

Browse files
kbondTimWolla
andcommitted
improve hash randomizer
Co-authored-by: Tim Düsterhus <[email protected]>
1 parent 8dd016a commit 5682652

File tree

3 files changed

+64
-46
lines changed

3 files changed

+64
-46
lines changed

src/Symfony/Component/Scheduler/Tests/RecurringMessageTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ public function __toString(): string
2929

3030
if (class_exists(Randomizer::class)) {
3131
$this->assertSame('30 0 * * *', (string) RecurringMessage::cron('#midnight', $object)->getTrigger());
32-
$this->assertSame('30 6 * * 2', (string) RecurringMessage::cron('#weekly', $object)->getTrigger());
32+
$this->assertSame('30 0 * * 3', (string) RecurringMessage::cron('#weekly', $object)->getTrigger());
3333
} else {
34-
$this->assertSame('56 2 * * *', (string) RecurringMessage::cron('#midnight', $object)->getTrigger());
35-
$this->assertSame('56 20 * * 0', (string) RecurringMessage::cron('#weekly', $object)->getTrigger());
34+
$this->assertSame('36 0 * * *', (string) RecurringMessage::cron('#midnight', $object)->getTrigger());
35+
$this->assertSame('36 0 * * 6', (string) RecurringMessage::cron('#weekly', $object)->getTrigger());
3636
}
3737
}
3838

src/Symfony/Component/Scheduler/Tests/Trigger/CronExpressionTriggerTest.php

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -36,54 +36,61 @@ public static function hashedExpressionProvider(): array
3636
if (class_exists(Randomizer::class)) {
3737
return [
3838
['# * * * *', '30 * * * *'],
39-
['# # * * *', '30 6 * * *'],
40-
['# # # * *', '30 6 3 * *'],
41-
['# # # # *', '30 6 3 7 *'],
42-
['# # # # #', '30 6 3 7 2'],
43-
['# # 1,15 1-11 *', '30 6 1,15 1-11 *'],
44-
['# # 1,15 * *', '30 6 1,15 * *'],
39+
['# # * * *', '30 0 * * *'],
40+
['# # # * *', '30 0 25 * *'],
41+
['# # # # *', '30 0 25 10 *'],
42+
['# # # # #', '30 0 25 10 5'],
43+
['# # 1,15 1-11 *', '30 0 1,15 1-11 *'],
44+
['# # 1,15 * *', '30 0 1,15 * *'],
4545
['#hourly', '30 * * * *'],
46-
['#daily', '30 6 * * *'],
47-
['#weekly', '30 6 * * 2'],
48-
['#weekly@midnight', '30 0 * * 2'],
49-
['#monthly', '30 6 3 * *'],
50-
['#monthly@midnight', '30 0 3 * *'],
51-
['#yearly', '30 6 3 7 *'],
52-
['#yearly@midnight', '30 0 3 7 *'],
53-
['#annually', '30 6 3 7 *'],
54-
['#annually@midnight', '30 0 3 7 *'],
46+
['#daily', '30 0 * * *'],
47+
['#weekly', '30 0 * * 3'],
48+
['#weekly@midnight', '30 0 * * 3'],
49+
['#monthly', '30 0 25 * *'],
50+
['#monthly@midnight', '30 0 25 * *'],
51+
['#yearly', '30 0 25 10 *'],
52+
['#yearly@midnight', '30 0 25 10 *'],
53+
['#annually', '30 0 25 10 *'],
54+
['#annually@midnight', '30 0 25 10 *'],
5555
['#midnight', '30 0 * * *'],
5656
['#(1-15) * * * *', '1 * * * *'],
5757
['#(1-15) * * * #(3-5)', '1 * * * 3'],
58-
['#(1-15) * # * #(3-5)', '1 * 3 * 3'],
58+
['#(1-15) * # * #(3-5)', '1 * 17 * 5'],
5959
];
6060
}
6161

6262
return [
63-
['# * * * *', '56 * * * *'],
64-
['# # * * *', '56 20 * * *'],
65-
['# # # * *', '56 20 1 * *'],
66-
['# # # # *', '56 20 1 9 *'],
67-
['# # # # #', '56 20 1 9 0'],
68-
['# # 1,15 1-11 *', '56 20 1,15 1-11 *'],
69-
['# # 1,15 * *', '56 20 1,15 * *'],
70-
['#hourly', '56 * * * *'],
71-
['#daily', '56 20 * * *'],
72-
['#weekly', '56 20 * * 0'],
73-
['#weekly@midnight', '56 2 * * 0'],
74-
['#monthly', '56 20 1 * *'],
75-
['#monthly@midnight', '56 2 1 * *'],
76-
['#yearly', '56 20 1 9 *'],
77-
['#yearly@midnight', '56 2 1 9 *'],
78-
['#annually', '56 20 1 9 *'],
79-
['#annually@midnight', '56 2 1 9 *'],
80-
['#midnight', '56 2 * * *'],
81-
['#(1-15) * * * *', '12 * * * *'],
82-
['#(1-15) * * * #(3-5)', '12 * * * 5'],
83-
['#(1-15) * # * #(3-5)', '12 * 1 * 5'],
63+
['# * * * *', '36 * * * *'],
64+
['# # * * *', '36 0 * * *'],
65+
['# # # * *', '36 0 14 * *'],
66+
['# # # # *', '36 0 14 3 *'],
67+
['# # # # #', '36 0 14 3 5'],
68+
['# # 1,15 1-11 *', '36 0 1,15 1-11 *'],
69+
['# # 1,15 * *', '36 0 1,15 * *'],
70+
['#hourly', '36 * * * *'],
71+
['#daily', '36 0 * * *'],
72+
['#weekly', '36 0 * * 6'],
73+
['#weekly@midnight', '36 0 * * 6'],
74+
['#monthly', '36 0 14 * *'],
75+
['#monthly@midnight', '36 0 14 * *'],
76+
['#yearly', '36 0 14 3 *'],
77+
['#yearly@midnight', '36 0 14 3 *'],
78+
['#annually', '36 0 14 3 *'],
79+
['#annually@midnight', '36 0 14 3 *'],
80+
['#midnight', '36 0 * * *'],
81+
['#(1-15) * * * *', '7 * * * *'],
82+
['#(1-15) * * * #(3-5)', '7 * * * 3'],
83+
['#(1-15) * # * #(3-5)', '7 * 1 * 5'],
8484
];
8585
}
8686

87+
public function testHashFieldsAreRandomizedIndependently()
88+
{
89+
$parts = \explode(' ', (string) CronExpressionTrigger::fromSpec('#(1-6) #(1-6) #(1-6) #(1-6) #(1-6)', 'some context'));
90+
91+
$this->assertNotCount(1, array_unique($parts));
92+
}
93+
8794
public function testFromHashWithStandardExpression()
8895
{
8996
$this->assertSame('56 20 1 9 0', (string) CronExpressionTrigger::fromSpec('56 20 1 9 0', 'some context'));

src/Symfony/Component/Scheduler/Trigger/CronExpressionTrigger.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,27 +87,38 @@ private static function parseHashed(string $expression, string $context): string
8787
return $expression;
8888
}
8989

90+
$hashEngine = self::hashEngine($context);
91+
9092
foreach ($parts as $position => $part) {
9193
if (preg_match('#^\#(\((\d+)-(\d+)\))?$#', $part, $matches)) {
92-
$parts[$position] = self::hashField(
94+
$parts[$position] = $hashEngine(
9395
(int) ($matches[2] ?? self::HASH_RANGES[$position][0]),
9496
(int) ($matches[3] ?? self::HASH_RANGES[$position][1]),
95-
$context,
9697
);
9798
}
9899
}
99100

100101
return implode(' ', $parts);
101102
}
102103

103-
private static function hashField(int $start, int $end, string $context): int
104+
/**
105+
* @return callable(int,int):int
106+
*/
107+
private static function hashEngine(string $context): callable
104108
{
105109
if (class_exists(Randomizer::class)) {
106-
return (new Randomizer(new Xoshiro256StarStar(hash('sha256', $context, true))))->getInt($start, $end);
110+
$randomizer = new Randomizer(new Xoshiro256StarStar(hash('sha256', $context, true)));
111+
112+
return static fn ($start, $end) => $randomizer->getInt($start, $end);
107113
}
108114

109-
$possibleValues = range($start, $end);
115+
$counter = 0;
116+
117+
return static function ($start, $end) use ($context, &$counter) {
118+
$possibleValues = range($start, $end);
119+
$counter++;
110120

111-
return $possibleValues[(int) fmod(hexdec(substr(md5($context), 0, 10)), \count($possibleValues))];
121+
return $possibleValues[(int) fmod(hexdec(substr(md5($context . '-' . $counter), 0, 10)), \count($possibleValues))];
122+
};
112123
}
113124
}

0 commit comments

Comments
 (0)