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

View file

@ -337,9 +337,6 @@ abstract class PhabricatorDaemonManagementWorkflow
array(
'class' => 'PhabricatorRepositoryPullLocalDaemon',
),
array(
'class' => 'PhabricatorGarbageCollectorDaemon',
),
array(
'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;
- **PhabricatorRepositoryPullLocalDaemon** daemons track repositories, for
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 =
@ -120,7 +121,7 @@ daemons launch, and split daemons across machines like this:
- `PhabricatorRepositoryPullLocalDaemon`: Run one copy on any machine.
On each web frontend which is not running a normal copy, run a copy
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
tasks from backing up. You can run them all on one machine or split them
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.
*
* Also performs garbage collection of old logs, caches, etc.
*
* @task garbage Garbage Collection
*/
final class PhabricatorTriggerDaemon
extends PhabricatorDaemon {
@ -9,6 +13,9 @@ final class PhabricatorTriggerDaemon
const COUNTER_VERSION = 'trigger.version';
const COUNTER_CURSOR = 'trigger.cursor';
private $garbageCollectors;
private $nextCollection;
protected function run() {
// 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
// processes or the daemon.
// We want to start the first GC cycle right away, not wait 4 hours.
$this->nextCollection = PhabricatorTime::getNow();
do {
$lock = PhabricatorGlobalLock::newLock('trigger');
@ -86,7 +96,9 @@ final class PhabricatorTriggerDaemon
$lock->unlock();
$this->sleep($this->getSleepDuration());
$sleep_duration = $this->getSleepDuration();
$sleep_duration = $this->runGarbageCollection($sleep_duration);
$this->sleep($sleep_duration);
} while (!$this->shouldExit());
}
@ -248,7 +260,7 @@ final class PhabricatorTriggerDaemon
* @return int Number of seconds to sleep for.
*/
private function getSleepDuration() {
$sleep = 60;
$sleep = 5;
$next_triggers = id(new PhabricatorWorkerTriggerQuery())
->setViewer($this->getViewer())
@ -290,4 +302,91 @@ final class PhabricatorTriggerDaemon
id(new PhabricatorWorkerTrigger())->establishConnection('w'),
$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();
}
}