Skip to content

Commit 004210d

Browse files
AntonTyutinandig
authored andcommitted
Avoid excessive slave restarts when multiple watched files change (php-pm#348)
1 parent 21e8a0a commit 004210d

1 file changed

Lines changed: 60 additions & 37 deletions

File tree

src/ProcessManager.php

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ class ProcessManager
128128
*/
129129
protected $port = 8080;
130130

131+
/**
132+
* @var bool
133+
*/
134+
protected $inChangesDetectionCycle = false;
135+
131136
/**
132137
* Whether the server is in the restart phase.
133138
*
@@ -169,7 +174,6 @@ class ProcessManager
169174
*/
170175
protected $lastWorkerErrorPrintBy;
171176

172-
protected $filesToTrack = [];
173177
protected $filesLastMTime = [];
174178
protected $filesLastMd5 = [];
175179

@@ -755,10 +759,32 @@ protected function commandFiles(array $data, ConnectionInterface $conn)
755759
try {
756760
$slave = $this->slaves->getByConnection($conn);
757761

762+
$start = microtime(true);
763+
764+
clearstatcache();
765+
766+
$newFilesCount = 0;
767+
$knownFiles = array_keys($this->filesLastMTime);
768+
$recentlyIncludedFiles = array_diff($data['files'], $knownFiles);
769+
foreach ($recentlyIncludedFiles as $filePath) {
770+
if (file_exists($filePath)) {
771+
$this->filesLastMTime[$filePath] = filemtime($filePath);
772+
$this->filesLastMd5[$filePath] = md5_file($filePath, true);
773+
$newFilesCount++;
774+
}
775+
}
776+
758777
if ($this->output->isVeryVerbose()) {
759-
$this->output->writeln(sprintf('Received %d files from %d', count($data['files']), $slave->getPort()));
778+
$this->output->writeln(
779+
sprintf(
780+
'Received %d new files from %d. Stats collection cycle: %u files, %.3f ms',
781+
$newFilesCount,
782+
$slave->getPort(),
783+
count($this->filesLastMTime),
784+
(microtime(true) - $start) * 1000
785+
)
786+
);
760787
}
761-
$this->filesToTrack = array_unique(array_merge($this->filesToTrack, $data['files']));
762788
} catch (\Exception $e) {
763789
// silent
764790
}
@@ -818,59 +844,54 @@ protected function bootstrapFailed($port)
818844
*/
819845
protected function checkChangedFiles($restartSlaves = true)
820846
{
821-
if ($this->inRestart) {
847+
if ($this->inChangesDetectionCycle) {
822848
return false;
823849
}
824850

825-
clearstatcache();
826-
827-
$reload = false;
828-
$filePath = '';
829851
$start = microtime(true);
852+
$hasChanged = false;
830853

831-
foreach ($this->filesToTrack as $idx => $filePath) {
854+
$this->inChangesDetectionCycle = true;
855+
856+
clearstatcache();
857+
858+
foreach ($this->filesLastMTime as $filePath => $knownMTime) {
832859
if (!file_exists($filePath)) {
833860
continue;
834861
}
835862

836-
$currentFileMTime = filemtime($filePath);
837-
838-
if (isset($this->filesLastMTime[$filePath])) {
839-
if ($this->filesLastMTime[$filePath] !== $currentFileMTime) {
840-
$this->filesLastMTime[$filePath] = $currentFileMTime;
841-
842-
$md5 = md5_file($filePath);
843-
if (!isset($this->filesLastMd5[$filePath]) || $md5 !== $this->filesLastMd5[$filePath]) {
844-
$this->filesLastMd5[$filePath] = $md5;
845-
$reload = true;
846-
847-
//since chances are high that this file will change again we
848-
//move this file to the beginning of the array, so next check is way faster.
849-
unset($this->filesToTrack[$idx]);
850-
array_unshift($this->filesToTrack, $filePath);
851-
break;
852-
}
853-
}
854-
} else {
855-
$this->filesLastMTime[$filePath] = $currentFileMTime;
863+
if ($knownMTime !== filemtime($filePath) && $this->filesLastMd5[$filePath] !== md5_file($filePath, true)) {
864+
$this->output->writeln(
865+
sprintf("<info>[%s] File %s has changed.</info>", date('d/M/Y:H:i:s O'), $filePath)
866+
);
867+
$hasChanged = true;
868+
break;
856869
}
857870
}
858871

859-
if ($reload && $restartSlaves) {
872+
if ($hasChanged) {
860873
$this->output->writeln(
861874
sprintf(
862-
"<info>[%s] File changed %s (detection %.3f, %d). Reloading workers.</info>",
875+
"<info>[%s] At least one of %u known files was changed. Reloading workers.</info>",
863876
date('d/M/Y:H:i:s O'),
864-
$filePath,
865-
microtime(true) - $start,
866-
count($this->filesToTrack)
877+
count($this->filesLastMTime)
867878
)
868879
);
869880

870-
$this->restartSlaves();
881+
if ($this->output->isVeryVerbose()) {
882+
$this->output->writeln(
883+
sprintf("Changes detection cycle length = %.3f ms", (microtime(true) - $start) * 1000)
884+
);
885+
}
886+
887+
if ($restartSlaves) {
888+
$this->restartSlaves();
889+
}
871890
}
872891

873-
return $reload;
892+
$this->inChangesDetectionCycle = false;
893+
894+
return $hasChanged;
874895
}
875896

876897
/**
@@ -995,6 +1016,9 @@ public function closeSlaves($graceful = false, $onSlaveClosed = null)
9951016
}
9961017
}
9971018

1019+
$this->filesLastMTime = [];
1020+
$this->filesLastMd5 = [];
1021+
9981022
if ($this->reloadTimeoutTimer !== null) {
9991023
$this->reloadTimeoutTimer->cancel();
10001024
}
@@ -1028,7 +1052,6 @@ public function restartSlaves()
10281052
}
10291053

10301054
$this->inRestart = true;
1031-
$this->output->writeln('Restarting all workers');
10321055

10331056
$this->closeSlaves();
10341057
$this->createSlaves();

0 commit comments

Comments
 (0)