Lines
100.00%
13 / 13
Methods
100.00%
3 / 3
Classes
100.00%
1 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| __construct | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| shouldShutdown | 100.00% | 8 / 8 | 100.00% | 1 / 1 | 4 | ||
| shutdown | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 2 | ||
| 15 | final readonly class SharedFileShutdown implements ShutdownInterface | |
| 16 | { | |
| 17 | public function __construct( | |
| 18 | private string $filePath, | |
| 19 | ) {} | |
| 20 | ||
| 21 | /** | |
| 22 | * Returns true when the file holds a shutdown time that is not in the future | |
| 23 | * and is later than the moment this worker started ($startTime). | |
| 24 | */ | |
| 25 | #[\Override] | |
| 26 | public function shouldShutdown(DateTimeInterface $startTime): bool | |
| 27 | { | |
| 28 | clearstatcache(false, $this->filePath); | |
| 29 | ||
| 30 | // a missing file means keep running | |
| 31 | $modified = @filemtime($this->filePath); | |
| 32 | if ($modified === false) { | |
| 33 | return false; | |
| 34 | } | |
| 35 | ||
| 36 | // The time in the file is only current while the file was not touched since: then it falls | |
| 37 | // in the second of the modification time. Otherwise (`touch`, or no time in it) use that second. | |
| 38 | $shutdownTime = ShutdownTime::parse(@file_get_contents($this->filePath)); | |
| 39 | if ($shutdownTime === null || (int) floor($shutdownTime) !== $modified) { | |
| 40 | $shutdownTime = $modified; | |
| 41 | } | |
| 42 | ||
| 43 | return ShutdownTime::isRequested($shutdownTime, $startTime, microtime(true)); | |
| 44 | } | |
| 45 | ||
| 46 | #[\Override] | |
| 47 | public function shutdown(?DateTimeInterface $shutdownTime = null): bool | |
| 48 | { | |
| 49 | $shutdownTime ??= new DateTimeImmutable(); | |
| 50 | ||
| 51 | // Rewrite the file in place, like `touch` in 5.x: an existing file keeps its owner and mode, and | |
| 52 | // the directory does not have to be writable. A worker that reads the file during the write sees | |
| 53 | // an empty or shorter time and at worst stops on its next check instead of this one. | |
| 54 | if (@file_put_contents($this->filePath, ShutdownTime::format($shutdownTime), LOCK_EX) === false) { | |
| 55 | return false; | |
| 56 | } | |
| 57 | ||
| 58 | return touch($this->filePath, (int) $shutdownTime->format('U')); | |
| 59 | } | |
| 60 | } |