|
17 | 17 | namespace Cake\Queue; |
18 | 18 |
|
19 | 19 | use BadMethodCallException; |
| 20 | +use Cake\Cache\Cache; |
20 | 21 | use Cake\Core\App; |
21 | 22 | use Cake\Log\Log; |
22 | 23 | use Enqueue\Client\Message as ClientMessage; |
@@ -119,6 +120,16 @@ public static function setConfig($key, $config = null): void |
119 | 120 | } |
120 | 121 | } |
121 | 122 |
|
| 123 | + if (!empty($config['uniqueCache'])) { |
| 124 | + $cacheDefaults = [ |
| 125 | + 'duration' => '+24 hours', |
| 126 | + ]; |
| 127 | + |
| 128 | + $cacheConfig = array_merge($cacheDefaults, $config['uniqueCache']); |
| 129 | + |
| 130 | + Cache::setConfig('Cake/Queue.queueUnique', $cacheConfig); |
| 131 | + } |
| 132 | + |
122 | 133 | /** @psalm-suppress InvalidPropertyAssignmentValue */ |
123 | 134 | static::$_config[$key] = $config; |
124 | 135 | } |
@@ -209,7 +220,33 @@ public static function push($className, array $data = [], array $options = []): |
209 | 220 |
|
210 | 221 | $name = $options['config'] ?? 'default'; |
211 | 222 |
|
212 | | - $config = static::getConfig($name); |
| 223 | + $config = static::getConfig($name) + [ |
| 224 | + 'logger' => null, |
| 225 | + ]; |
| 226 | + |
| 227 | + $logger = $config['logger'] ? Log::engine($config['logger']) : null; |
| 228 | + |
| 229 | + /** @psalm-suppress InvalidPropertyFetch */ |
| 230 | + if (!empty($class::$shouldBeUnique)) { |
| 231 | + if (!Cache::getConfig('Cake/Queue.queueUnique')) { |
| 232 | + throw new InvalidArgumentException( |
| 233 | + "$class::\$shouldBeUnique is set to `true` but `uniqueCache` configuration is missing." |
| 234 | + ); |
| 235 | + } |
| 236 | + |
| 237 | + $uniqueId = static::getUniqueId($class, $method, $data); |
| 238 | + |
| 239 | + if (Cache::read($uniqueId, 'Cake/Queue.queueUnique')) { |
| 240 | + if ($logger) { |
| 241 | + $logger->debug( |
| 242 | + "An identical instance of $class already exists on the queue. This push will be ignored." |
| 243 | + ); |
| 244 | + } |
| 245 | + |
| 246 | + return; |
| 247 | + } |
| 248 | + } |
| 249 | + |
213 | 250 | $queue = $options['queue'] ?? $config['queue'] ?? 'default'; |
214 | 251 |
|
215 | 252 | $message = new ClientMessage([ |
@@ -237,5 +274,31 @@ public static function push($className, array $data = [], array $options = []): |
237 | 274 |
|
238 | 275 | $client = static::engine($name); |
239 | 276 | $client->sendEvent($queue, $message); |
| 277 | + |
| 278 | + /** @psalm-suppress InvalidPropertyFetch */ |
| 279 | + if (!empty($class::$shouldBeUnique)) { |
| 280 | + $uniqueId = static::getUniqueId($class, $method, $data); |
| 281 | + |
| 282 | + Cache::add($uniqueId, true, 'Cake/Queue.queueUnique'); |
| 283 | + } |
| 284 | + } |
| 285 | + |
| 286 | + /** |
| 287 | + * @param string $class Class name |
| 288 | + * @param string $method Method name |
| 289 | + * @param array $data Message data |
| 290 | + * @return string |
| 291 | + */ |
| 292 | + public static function getUniqueId(string $class, string $method, array $data): string |
| 293 | + { |
| 294 | + sort($data); |
| 295 | + |
| 296 | + $hashInput = implode([ |
| 297 | + $class, |
| 298 | + $method, |
| 299 | + json_encode($data), |
| 300 | + ]); |
| 301 | + |
| 302 | + return hash('md5', $hashInput); |
240 | 303 | } |
241 | 304 | } |
0 commit comments