1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-20 12:30:56 +01:00

Merge GC daemon into Trigger daemon

Summary:
Fixes T7352. This reduces the memory footprint for instances by combining these two similar daemons into one daemon which handles the responsibilities of both.

The fit isn't 100% perfect here but it's pretty close, and the GC daemon is fairly trivial.

Test Plan:
  - Adjusted all the numbers to small numbers (5 second sleep, 120 second GC length).
  - Added a ton of logging.
  - Started trigger daemon.
    - Saw it run a GC cycle.
    - Saw it reschedule another cycle after 120 seconds (adjusted down from 4 hours).
  - Reverted all the logging/small numbers.
  - Ran `bin/phd start`, saw stable trigger daemon running.
  - Grepped for removed daemon class name.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T7352

Differential Revision: https://secure.phabricator.com/D11872
This commit is contained in:
epriestley 2015-02-23 18:39:01 -08:00
parent af303f458b
commit a3518e19a5
5 changed files with 104 additions and 47 deletions

View file

@ -1838,7 +1838,6 @@ phutil_register_library_map(array(
'PhabricatorGDSetupCheck' => 'applications/config/check/PhabricatorGDSetupCheck.php', 'PhabricatorGDSetupCheck' => 'applications/config/check/PhabricatorGDSetupCheck.php',
'PhabricatorGarbageCollector' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php', 'PhabricatorGarbageCollector' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php',
'PhabricatorGarbageCollectorConfigOptions' => 'applications/config/option/PhabricatorGarbageCollectorConfigOptions.php', 'PhabricatorGarbageCollectorConfigOptions' => 'applications/config/option/PhabricatorGarbageCollectorConfigOptions.php',
'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollectorDaemon.php',
'PhabricatorGestureUIExample' => 'applications/uiexample/examples/PhabricatorGestureUIExample.php', 'PhabricatorGestureUIExample' => 'applications/uiexample/examples/PhabricatorGestureUIExample.php',
'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php', 'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php',
'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php', 'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php',
@ -5122,7 +5121,6 @@ phutil_register_library_map(array(
'PhabricatorGDSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorGDSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorGarbageCollector' => 'Phobject', 'PhabricatorGarbageCollector' => 'Phobject',
'PhabricatorGarbageCollectorConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorGarbageCollectorConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon',
'PhabricatorGestureUIExample' => 'PhabricatorUIExample', 'PhabricatorGestureUIExample' => 'PhabricatorUIExample',
'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream',
'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider',

View file

@ -337,9 +337,6 @@ abstract class PhabricatorDaemonManagementWorkflow
array( array(
'class' => 'PhabricatorRepositoryPullLocalDaemon', 'class' => 'PhabricatorRepositoryPullLocalDaemon',
), ),
array(
'class' => 'PhabricatorGarbageCollectorDaemon',
),
array( array(
'class' => 'PhabricatorTriggerDaemon', 'class' => 'PhabricatorTriggerDaemon',
), ),

View file

@ -70,7 +70,8 @@ You can get a list of launchable daemons with **phd list**:
- **PhabricatorTaskmasterDaemon** performs work from a task queue; - **PhabricatorTaskmasterDaemon** performs work from a task queue;
- **PhabricatorRepositoryPullLocalDaemon** daemons track repositories, for - **PhabricatorRepositoryPullLocalDaemon** daemons track repositories, for
more information see @{article:Diffusion User Guide}; and more information see @{article:Diffusion User Guide}; and
- **PhabricatorGarbageCollectorDaemon** cleans up old logs and caches. - **PhabricatorTriggerDaemon** schedules event triggers and cleans up old
logs and caches.
= Debugging and Tuning = = Debugging and Tuning =
@ -120,7 +121,7 @@ daemons launch, and split daemons across machines like this:
- `PhabricatorRepositoryPullLocalDaemon`: Run one copy on any machine. - `PhabricatorRepositoryPullLocalDaemon`: Run one copy on any machine.
On each web frontend which is not running a normal copy, run a copy On each web frontend which is not running a normal copy, run a copy
with the `--no-discovery` flag. with the `--no-discovery` flag.
- `PhabricatorGarbageCollectorDaemon`: Run one copy on any machine. - `PhabricatorTriggerDaemon`: Run one copy on any machine.
- `PhabricatorTaskmasterDaemon`: Run as many copies as you need to keep - `PhabricatorTaskmasterDaemon`: Run as many copies as you need to keep
tasks from backing up. You can run them all on one machine or split them tasks from backing up. You can run them all on one machine or split them
across machines. across machines.

View file

@ -1,38 +0,0 @@
<?php
/**
* Collects old logs and caches to reduce the amount of data stored in the
* database.
*/
final class PhabricatorGarbageCollectorDaemon extends PhabricatorDaemon {
protected function run() {
$collectors = id(new PhutilSymbolLoader())
->setAncestorClass('PhabricatorGarbageCollector')
->loadObjects();
do {
foreach ($collectors as $name => $collector) {
$more_garbage = false;
do {
if ($more_garbage) {
$this->log(pht('Collecting more garbage with "%s".', $name));
} else {
$this->log(pht('Collecting garbage with "%s".', $name));
}
$more_garbage = $collector->collectGarbage();
$this->stillWorking();
} while ($more_garbage);
}
// We made it to the end of the run cycle of every GC, so we're more or
// less caught up. Ease off the GC loop so we don't keep doing table
// scans just to delete a handful of rows; wake up in a few hours.
$this->log(pht('All caught up, waiting for more garbage.'));
$this->sleep(4 * (60 * 60));
} while (!$this->shouldExit());
}
}

View file

@ -2,6 +2,10 @@
/** /**
* Schedule and execute event triggers, which run code at specific times. * Schedule and execute event triggers, which run code at specific times.
*
* Also performs garbage collection of old logs, caches, etc.
*
* @task garbage Garbage Collection
*/ */
final class PhabricatorTriggerDaemon final class PhabricatorTriggerDaemon
extends PhabricatorDaemon { extends PhabricatorDaemon {
@ -9,6 +13,9 @@ final class PhabricatorTriggerDaemon
const COUNTER_VERSION = 'trigger.version'; const COUNTER_VERSION = 'trigger.version';
const COUNTER_CURSOR = 'trigger.cursor'; const COUNTER_CURSOR = 'trigger.cursor';
private $garbageCollectors;
private $nextCollection;
protected function run() { protected function run() {
// The trigger daemon is a low-level infrastructure daemon which schedules // The trigger daemon is a low-level infrastructure daemon which schedules
@ -54,6 +61,9 @@ final class PhabricatorTriggerDaemon
// trying to reschedule events after an update could race with other web // trying to reschedule events after an update could race with other web
// processes or the daemon. // processes or the daemon.
// We want to start the first GC cycle right away, not wait 4 hours.
$this->nextCollection = PhabricatorTime::getNow();
do { do {
$lock = PhabricatorGlobalLock::newLock('trigger'); $lock = PhabricatorGlobalLock::newLock('trigger');
@ -86,7 +96,9 @@ final class PhabricatorTriggerDaemon
$lock->unlock(); $lock->unlock();
$this->sleep($this->getSleepDuration()); $sleep_duration = $this->getSleepDuration();
$sleep_duration = $this->runGarbageCollection($sleep_duration);
$this->sleep($sleep_duration);
} while (!$this->shouldExit()); } while (!$this->shouldExit());
} }
@ -248,7 +260,7 @@ final class PhabricatorTriggerDaemon
* @return int Number of seconds to sleep for. * @return int Number of seconds to sleep for.
*/ */
private function getSleepDuration() { private function getSleepDuration() {
$sleep = 60; $sleep = 5;
$next_triggers = id(new PhabricatorWorkerTriggerQuery()) $next_triggers = id(new PhabricatorWorkerTriggerQuery())
->setViewer($this->getViewer()) ->setViewer($this->getViewer())
@ -290,4 +302,91 @@ final class PhabricatorTriggerDaemon
id(new PhabricatorWorkerTrigger())->establishConnection('w'), id(new PhabricatorWorkerTrigger())->establishConnection('w'),
$counter_name); $counter_name);
} }
/* -( Garbage Collection )------------------------------------------------- */
/**
* Run the garbage collector for up to a specified number of seconds.
*
* @param int Number of seconds the GC may run for.
* @return int Number of seconds remaining in the time budget.
* @task garbage
*/
private function runGarbageCollection($duration) {
$run_until = (PhabricatorTime::getNow() + $duration);
// NOTE: We always run at least one GC cycle to make sure the GC can make
// progress even if the trigger queue is busy.
do {
$more_garbage = $this->updateGarbageCollection();
if (!$more_garbage) {
// If we don't have any more collection work to perform, we're all
// done.
break;
}
} while (PhabricatorTime::getNow() <= $run_until);
$remaining = max(0, $run_until - PhabricatorTime::getNow());
return $remaining;
}
/**
* Update garbage collection, possibly collecting a small amount of garbage.
*
* @return bool True if there is more garbage to collect.
* @task garbage
*/
private function updateGarbageCollection() {
// If we're ready to start the next collection cycle, load all the
// collectors.
$next = $this->nextCollection;
if ($next && (PhabricatorTime::getNow() >= $next)) {
$this->nextCollection = null;
$this->garbageCollectors = $this->loadGarbageCollectors();
}
// If we're in a collection cycle, continue collection.
if ($this->garbageCollectors) {
foreach ($this->garbageCollectors as $key => $collector) {
$more_garbage = $collector->collectGarbage();
if (!$more_garbage) {
unset($this->garbageCollectors[$key]);
}
// We only run one collection per call, to prevent triggers from being
// thrown too far off schedule if there's a lot of garbage to collect.
break;
}
if ($this->garbageCollectors) {
// If we have more work to do, return true.
return true;
}
// Otherwise, reschedule another cycle in 4 hours.
$now = PhabricatorTime::getNow();
$wait = phutil_units('4 hours in seconds');
$this->nextCollection = $now + $wait;
}
return false;
}
/**
* Load all of the available garbage collectors.
*
* @return list<PhabricatorGarbageCollector> Garbage collectors.
* @task garbage
*/
private function loadGarbageCollectors() {
return id(new PhutilSymbolLoader())
->setAncestorClass('PhabricatorGarbageCollector')
->loadObjects();
}
} }