4 * @task update Updating Leases
5 * @task command Processing Commands
6 * @task allocator Drydock Allocator
7 * @task acquire Acquiring Leases
8 * @task activate Activating Leases
9 * @task release Releasing Leases
10 * @task break Breaking Leases
11 * @task destroy Destroying Leases
13 final class DrydockLeaseUpdateWorker
extends DrydockWorker
{
15 protected function doWork() {
16 $lease_phid = $this->getTaskDataValue('leasePHID');
18 $hash = PhabricatorHash
::digestForIndex($lease_phid);
19 $lock_key = 'drydock.lease:'.$hash;
21 $lock = PhabricatorGlobalLock
::newLock($lock_key)
25 $lease = $this->loadLease($lease_phid);
26 $this->handleUpdate($lease);
27 } catch (Exception
$ex) {
29 $this->flushDrydockTaskQueue();
37 /* -( Updating Leases )---------------------------------------------------- */
43 private function handleUpdate(DrydockLease
$lease) {
45 $this->updateLease($lease);
46 } catch (DrydockAcquiredBrokenResourceException
$ex) {
47 // If this lease acquired a resource but failed to activate, we don't
48 // need to break the lease. We can throw it back in the pool and let
49 // it take another shot at acquiring a new resource.
51 // Before we throw it back, release any locks the lease is holding.
52 DrydockSlotLock
::releaseLocks($lease->getPHID());
55 ->setStatus(DrydockLeaseStatus
::STATUS_PENDING
)
56 ->setResourcePHID(null)
60 DrydockLeaseReacquireLogType
::LOGCONST
,
62 'class' => get_class($ex),
63 'message' => $ex->getMessage(),
66 $this->yieldLease($lease, $ex);
67 } catch (Exception
$ex) {
68 if ($this->isTemporaryException($ex)) {
69 $this->yieldLease($lease, $ex);
71 $this->breakLease($lease, $ex);
80 private function updateLease(DrydockLease
$lease) {
81 $this->processLeaseCommands($lease);
83 $lease_status = $lease->getStatus();
84 switch ($lease_status) {
85 case DrydockLeaseStatus
::STATUS_PENDING
:
86 $this->executeAllocator($lease);
88 case DrydockLeaseStatus
::STATUS_ACQUIRED
:
89 $this->activateLease($lease);
91 case DrydockLeaseStatus
::STATUS_ACTIVE
:
94 case DrydockLeaseStatus
::STATUS_RELEASED
:
95 case DrydockLeaseStatus
::STATUS_BROKEN
:
96 $this->destroyLease($lease);
98 case DrydockLeaseStatus
::STATUS_DESTROYED
:
102 $this->yieldIfExpiringLease($lease);
109 private function yieldLease(DrydockLease
$lease, Exception
$ex) {
110 $duration = $this->getYieldDurationFromException($ex);
113 DrydockLeaseActivationYieldLogType
::LOGCONST
,
115 'duration' => $duration,
118 throw new PhabricatorWorkerYieldException($duration);
122 /* -( Processing Commands )------------------------------------------------ */
128 private function processLeaseCommands(DrydockLease
$lease) {
129 if (!$lease->canReceiveCommands()) {
133 $this->checkLeaseExpiration($lease);
135 $commands = $this->loadCommands($lease->getPHID());
136 foreach ($commands as $command) {
137 if (!$lease->canReceiveCommands()) {
141 $this->processLeaseCommand($lease, $command);
144 ->setIsConsumed(true)
153 private function processLeaseCommand(
155 DrydockCommand
$command) {
156 switch ($command->getCommand()) {
157 case DrydockCommand
::COMMAND_RELEASE
:
158 $this->releaseLease($lease);
164 /* -( Drydock Allocator )-------------------------------------------------- */
168 * Find or build a resource which can satisfy a given lease request, then
171 * @param DrydockLease Requested lease.
175 private function executeAllocator(DrydockLease
$lease) {
176 $blueprints = $this->loadBlueprintsForAllocatingLease($lease);
178 // If we get nothing back, that means no blueprint is defined which can
179 // ever build the requested resource. This is a permanent failure, since
180 // we don't expect to succeed no matter how many times we try.
182 throw new PhabricatorWorkerPermanentFailureException(
184 'No active Drydock blueprint exists which can ever allocate a '.
185 'resource for lease "%s".',
189 // First, try to find a suitable open resource which we can acquire a new
191 $resources = $this->loadAcquirableResourcesForLease($blueprints, $lease);
193 list($free_resources, $used_resources) = $this->partitionResources(
197 $resource = $this->leaseAnyResource($lease, $free_resources);
202 // We're about to try creating a resource. If we're already creating
203 // something, just yield until that resolves.
205 $this->yieldForPendingResources($lease);
207 // We haven't been able to lease an existing resource yet, so now we try to
208 // create one. We may still have some less-desirable "used" resources that
209 // we'll sometimes try to lease later if we fail to allocate a new resource.
211 $resource = $this->newLeasedResource($lease, $blueprints);
216 // We haven't been able to lease a desirable "free" resource or create a
217 // new resource. Try to lease a "used" resource.
219 $resource = $this->leaseAnyResource($lease, $used_resources);
224 // If this lease has already triggered a reclaim, just yield and wait for
226 $this->yieldForReclaimingResources($lease);
228 // Try to reclaim a resource. This will yield if it reclaims something.
229 $this->reclaimAnyResource($lease, $blueprints);
231 // We weren't able to lease, create, or reclaim any resources. We just have
232 // to wait for resources to become available.
235 DrydockLeaseWaitingForResourcesLogType
::LOGCONST
,
237 'blueprintPHIDs' => mpull($blueprints, 'getPHID'),
240 throw new PhabricatorWorkerYieldException(15);
243 private function reclaimAnyResource(DrydockLease
$lease, array $blueprints) {
244 assert_instances_of($blueprints, 'DrydockBlueprint');
246 $blueprints = $this->rankBlueprints($blueprints, $lease);
248 // Try to actively reclaim unused resources. If we succeed, jump back
249 // into the queue in an effort to claim it.
251 foreach ($blueprints as $blueprint) {
252 $reclaimed = $this->reclaimResources($blueprint, $lease);
256 DrydockLeaseReclaimLogType
::LOGCONST
,
258 'resourcePHIDs' => array($reclaimed->getPHID()),
261 // Yield explicitly here: we'll be awakened when the resource is
264 throw new PhabricatorWorkerYieldException(15);
269 private function yieldForPendingResources(DrydockLease
$lease) {
270 // See T13677. If this lease has already triggered the allocation of
271 // one or more resources and they are still pending, just yield and
274 $viewer = $this->getViewer();
276 $phids = $lease->getAllocatedResourcePHIDs();
281 $resources = id(new DrydockResourceQuery())
286 DrydockResourceStatus
::STATUS_PENDING
,
295 DrydockLeaseWaitingForActivationLogType
::LOGCONST
,
297 'resourcePHIDs' => mpull($resources, 'getPHID'),
300 throw new PhabricatorWorkerYieldException(15);
303 private function yieldForReclaimingResources(DrydockLease
$lease) {
304 $viewer = $this->getViewer();
306 $phids = $lease->getReclaimedResourcePHIDs();
311 $resources = id(new DrydockResourceQuery())
316 DrydockResourceStatus
::STATUS_ACTIVE
,
317 DrydockResourceStatus
::STATUS_RELEASED
,
326 DrydockLeaseWaitingForReclamationLogType
::LOGCONST
,
328 'resourcePHIDs' => mpull($resources, 'getPHID'),
331 throw new PhabricatorWorkerYieldException(15);
334 private function newLeasedResource(
337 assert_instances_of($blueprints, 'DrydockBlueprint');
339 $usable_blueprints = $this->removeOverallocatedBlueprints(
343 // If we get nothing back here, some blueprint claims it can eventually
344 // satisfy the lease, just not right now. This is a temporary failure,
345 // and we expect allocation to succeed eventually.
347 // Return, try to lease a "used" resource, and continue from there.
349 if (!$usable_blueprints) {
353 $usable_blueprints = $this->rankBlueprints($usable_blueprints, $lease);
355 $new_resources = $this->newResources($lease, $usable_blueprints);
356 if (!$new_resources) {
357 // If we were unable to create any new resources, return and
358 // try to lease a "used" resource.
362 $new_resources = $this->removeUnacquirableResources(
365 if (!$new_resources) {
366 // If we make it here, we just built a resource but aren't allowed
367 // to acquire it. We expect this to happen if the resource prevents
368 // acquisition until it activates, which is common when a resource
369 // needs to perform setup steps.
371 // Explicitly yield and wait for activation, since we don't want to
372 // lease a "used" resource.
374 throw new PhabricatorWorkerYieldException(15);
377 $resource = $this->leaseAnyResource($lease, $new_resources);
382 // We may not be able to lease a resource even if we just built it:
383 // another process may snatch it up before we can lease it. This should
384 // be rare, but is not concerning. Just try to build another resource.
386 // We likely could try to build the next resource immediately, but err on
387 // the side of caution and yield for now, at least until this code is
390 throw new PhabricatorWorkerYieldException(15);
393 private function partitionResources(
397 assert_instances_of($resources, 'DrydockResource');
398 $viewer = $this->getViewer();
400 $lease_statuses = array(
401 DrydockLeaseStatus
::STATUS_PENDING
,
402 DrydockLeaseStatus
::STATUS_ACQUIRED
,
403 DrydockLeaseStatus
::STATUS_ACTIVE
,
406 // Partition resources into "free" resources (which we can try to lease
407 // immediately) and "used" resources, which we can only to lease after we
408 // fail to allocate a new resource.
410 // "Free" resources are unleased and/or prefer reuse over allocation.
411 // "Used" resources are leased and prefer allocation over reuse.
413 $free_resources = array();
414 $used_resources = array();
416 foreach ($resources as $resource) {
417 $blueprint = $resource->getBlueprint();
419 if (!$blueprint->shouldAllocateSupplementalResource($resource, $lease)) {
420 $free_resources[] = $resource;
424 $leases = id(new DrydockLeaseQuery())
426 ->withResourcePHIDs(array($resource->getPHID()))
427 ->withStatuses($lease_statuses)
431 $free_resources[] = $resource;
435 $used_resources[] = $resource;
438 return array($free_resources, $used_resources);
441 private function newResources(
444 assert_instances_of($blueprints, 'DrydockBlueprint');
446 $resources = array();
447 $exceptions = array();
448 foreach ($blueprints as $blueprint) {
451 $resources[] = $this->allocateResource($blueprint, $lease);
453 // Bail after allocating one resource, we don't need any more than
456 } catch (Exception
$ex) {
458 } catch (Throwable
$ex) {
463 // This failure is not normally expected, so log it. It can be
464 // caused by something mundane and recoverable, however (see below
467 // We log to the blueprint separately from the log to the lease:
468 // the lease is not attached to a blueprint yet so the lease log
469 // will not show up on the blueprint; more than one blueprint may
470 // fail; and the lease is not really impacted (and won't log) if at
471 // least one blueprint actually works.
473 $blueprint->logEvent(
474 DrydockResourceAllocationFailureLogType
::LOGCONST
,
476 'class' => get_class($caught),
477 'message' => $caught->getMessage(),
480 $exceptions[] = $caught;
485 // If one or more blueprints claimed that they would be able to allocate
486 // resources but none are actually able to allocate resources, log the
487 // failure and yield so we try again soon.
489 // This can happen if some unexpected issue occurs during allocation
490 // (for example, a call to build a VM fails for some reason) or if we
491 // raced another allocator and the blueprint is now full.
493 $ex = new PhutilAggregateException(
495 'All blueprints failed to allocate a suitable new resource when '.
496 'trying to allocate lease ("%s").',
501 DrydockLeaseAllocationFailureLogType
::LOGCONST
,
503 'class' => get_class($ex),
504 'message' => $ex->getMessage(),
514 private function leaseAnyResource(
517 assert_instances_of($resources, 'DrydockResource');
523 $resources = $this->rankResources($resources, $lease);
525 $exceptions = array();
529 foreach ($resources as $resource) {
531 $this->acquireLease($resource, $lease);
532 $allocated = $resource;
534 } catch (DrydockResourceLockException
$ex) {
535 // We need to lock the resource to actually acquire it. If we aren't
536 // able to acquire the lock quickly enough, we can yield and try again
539 } catch (DrydockSlotLockException
$ex) {
540 // This also just indicates we ran into some kind of contention,
541 // probably from another lease. Just yield.
543 } catch (DrydockAcquiredBrokenResourceException
$ex) {
544 // If a resource was reclaimed or destroyed by the time we actually
545 // got around to acquiring it, we just got unlucky.
547 } catch (PhabricatorWorkerYieldException
$ex) {
548 // We can be told to yield, particularly by the supplemental allocator
549 // trying to give us a supplemental resource.
551 } catch (Exception
$ex) {
561 throw new PhabricatorWorkerYieldException(15);
564 throw new PhutilAggregateException(
566 'Unable to acquire lease "%s" on any resource.',
573 * Get all the concrete @{class:DrydockBlueprint}s which can possibly
574 * build a resource to satisfy a lease.
576 * @param DrydockLease Requested lease.
577 * @return list<DrydockBlueprint> List of qualifying blueprints.
580 private function loadBlueprintsForAllocatingLease(
581 DrydockLease
$lease) {
582 $viewer = $this->getViewer();
584 $impls = DrydockBlueprintImplementation
::getAllForAllocatingLease($lease);
589 $blueprint_phids = $lease->getAllowedBlueprintPHIDs();
590 if (!$blueprint_phids) {
591 $lease->logEvent(DrydockLeaseNoBlueprintsLogType
::LOGCONST
);
595 $query = id(new DrydockBlueprintQuery())
597 ->withPHIDs($blueprint_phids)
598 ->withBlueprintClasses(array_keys($impls))
599 ->withDisabled(false);
601 // The Drydock application itself is allowed to authorize anything. This
602 // is primarily used for leases generated by CLI administrative tools.
603 $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
605 $authorizing_phid = $lease->getAuthorizingPHID();
606 if ($authorizing_phid != $drydock_phid) {
607 $blueprints = id(clone $query)
608 ->withAuthorizedPHIDs(array($authorizing_phid))
611 // If we didn't hit any blueprints, check if this is an authorization
612 // problem: re-execute the query without the authorization constraint.
613 // If the second query hits blueprints, the overall configuration is
614 // fine but this is an authorization problem. If the second query also
615 // comes up blank, this is some other kind of configuration issue so
616 // we fall through to the default pathway.
617 $all_blueprints = $query->execute();
618 if ($all_blueprints) {
620 DrydockLeaseNoAuthorizationsLogType
::LOGCONST
,
622 'authorizingPHID' => $authorizing_phid,
628 $blueprints = $query->execute();
632 foreach ($blueprints as $key => $blueprint) {
633 if (!$blueprint->canEverAllocateResourceForLease($lease)) {
637 $keep[$key] = $blueprint;
645 * Load a list of all resources which a given lease can possibly be
648 * @param list<DrydockBlueprint> Blueprints which may produce suitable
650 * @param DrydockLease Requested lease.
651 * @return list<DrydockResource> Resources which may be able to allocate
655 private function loadAcquirableResourcesForLease(
657 DrydockLease
$lease) {
658 assert_instances_of($blueprints, 'DrydockBlueprint');
659 $viewer = $this->getViewer();
661 $resources = id(new DrydockResourceQuery())
663 ->withBlueprintPHIDs(mpull($blueprints, 'getPHID'))
664 ->withTypes(array($lease->getResourceType()))
667 DrydockResourceStatus
::STATUS_ACTIVE
,
671 return $this->removeUnacquirableResources($resources, $lease);
676 * Remove resources which can not be acquired by a given lease from a list.
678 * @param list<DrydockResource> Candidate resources.
679 * @param DrydockLease Acquiring lease.
680 * @return list<DrydockResource> Resources which the lease may be able to
684 private function removeUnacquirableResources(
686 DrydockLease
$lease) {
688 foreach ($resources as $key => $resource) {
689 $blueprint = $resource->getBlueprint();
691 if (!$blueprint->canAcquireLeaseOnResource($resource, $lease)) {
695 $keep[$key] = $resource;
703 * Remove blueprints which are too heavily allocated to build a resource for
704 * a lease from a list of blueprints.
706 * @param list<DrydockBlueprint> List of blueprints.
707 * @return list<DrydockBlueprint> List with blueprints that can not allocate
708 * a resource for the lease right now removed.
711 private function removeOverallocatedBlueprints(
713 DrydockLease
$lease) {
714 assert_instances_of($blueprints, 'DrydockBlueprint');
718 foreach ($blueprints as $key => $blueprint) {
719 if (!$blueprint->canAllocateResourceForLease($lease)) {
723 $keep[$key] = $blueprint;
731 * Rank blueprints by suitability for building a new resource for a
734 * @param list<DrydockBlueprint> List of blueprints.
735 * @param DrydockLease Requested lease.
736 * @return list<DrydockBlueprint> Ranked list of blueprints.
739 private function rankBlueprints(array $blueprints, DrydockLease
$lease) {
740 assert_instances_of($blueprints, 'DrydockBlueprint');
742 // TODO: Implement improvements to this ranking algorithm if they become
744 shuffle($blueprints);
751 * Rank resources by suitability for allocating a particular lease.
753 * @param list<DrydockResource> List of resources.
754 * @param DrydockLease Requested lease.
755 * @return list<DrydockResource> Ranked list of resources.
758 private function rankResources(array $resources, DrydockLease
$lease) {
759 assert_instances_of($resources, 'DrydockResource');
761 // TODO: Implement improvements to this ranking algorithm if they become
770 * Perform an actual resource allocation with a particular blueprint.
772 * @param DrydockBlueprint The blueprint to allocate a resource from.
773 * @param DrydockLease Requested lease.
774 * @return DrydockResource Allocated resource.
777 private function allocateResource(
778 DrydockBlueprint
$blueprint,
779 DrydockLease
$lease) {
780 $resource = $blueprint->allocateResource($lease);
781 $this->validateAllocatedResource($blueprint, $resource, $lease);
783 // If this resource was allocated as a pending resource, queue a task to
785 if ($resource->getStatus() == DrydockResourceStatus
::STATUS_PENDING
) {
787 $lease->addAllocatedResourcePHIDs(
789 $resource->getPHID(),
793 PhabricatorWorker
::scheduleTask(
794 'DrydockResourceUpdateWorker',
796 'resourcePHID' => $resource->getPHID(),
798 // This task will generally yield while the resource activates, so
799 // wake it back up once the resource comes online. Most of the time,
800 // we'll be able to lease the newly activated resource.
801 'awakenOnActivation' => array(
802 $this->getCurrentWorkerTaskID(),
806 'objectPHID' => $resource->getPHID(),
815 * Check that the resource a blueprint allocated is roughly the sort of
818 * @param DrydockBlueprint Blueprint which built the resource.
819 * @param wild Thing which the blueprint claims is a valid resource.
820 * @param DrydockLease Lease the resource was allocated for.
824 private function validateAllocatedResource(
825 DrydockBlueprint
$blueprint,
827 DrydockLease
$lease) {
829 if (!($resource instanceof DrydockResource
)) {
832 'Blueprint "%s" (of type "%s") is not properly implemented: %s must '.
833 'return an object of type %s or throw, but returned something else.',
834 $blueprint->getBlueprintName(),
835 $blueprint->getClassName(),
836 'allocateResource()',
840 if (!$resource->isAllocatedResource()) {
843 'Blueprint "%s" (of type "%s") is not properly implemented: %s '.
844 'must actually allocate the resource it returns.',
845 $blueprint->getBlueprintName(),
846 $blueprint->getClassName(),
847 'allocateResource()'));
850 $resource_type = $resource->getType();
851 $lease_type = $lease->getResourceType();
853 if ($resource_type !== $lease_type) {
856 'Blueprint "%s" (of type "%s") is not properly implemented: it '.
857 'built a resource of type "%s" to satisfy a lease requesting a '.
858 'resource of type "%s".',
859 $blueprint->getBlueprintName(),
860 $blueprint->getClassName(),
866 private function reclaimResources(
867 DrydockBlueprint
$blueprint,
868 DrydockLease
$lease) {
869 $viewer = $this->getViewer();
871 $resources = id(new DrydockResourceQuery())
873 ->withBlueprintPHIDs(array($blueprint->getPHID()))
876 DrydockResourceStatus
::STATUS_ACTIVE
,
880 // TODO: We could be much smarter about this and try to release long-unused
881 // resources, resources with many similar copies, old resources, resources
882 // that are cheap to rebuild, etc.
885 foreach ($resources as $resource) {
886 if ($this->canReclaimResource($resource)) {
887 $this->reclaimResource($resource, $lease);
896 /* -( Acquiring Leases )--------------------------------------------------- */
900 * Perform an actual lease acquisition on a particular resource.
902 * @param DrydockResource Resource to acquire a lease on.
903 * @param DrydockLease Lease to acquire.
907 private function acquireLease(
908 DrydockResource
$resource,
909 DrydockLease
$lease) {
911 $blueprint = $resource->getBlueprint();
912 $blueprint->acquireLease($resource, $lease);
914 $this->validateAcquiredLease($blueprint, $resource, $lease);
916 // If this lease has been acquired but not activated, queue a task to
918 if ($lease->getStatus() == DrydockLeaseStatus
::STATUS_ACQUIRED
) {
922 'leasePHID' => $lease->getPHID(),
925 'objectPHID' => $lease->getPHID(),
932 * Make sure that a lease was really acquired properly.
934 * @param DrydockBlueprint Blueprint which created the resource.
935 * @param DrydockResource Resource which was acquired.
936 * @param DrydockLease The lease which was supposedly acquired.
940 private function validateAcquiredLease(
941 DrydockBlueprint
$blueprint,
942 DrydockResource
$resource,
943 DrydockLease
$lease) {
945 if (!$lease->isAcquiredLease()) {
948 'Blueprint "%s" (of type "%s") is not properly implemented: it '.
949 'returned from "%s" without acquiring a lease.',
950 $blueprint->getBlueprintName(),
951 $blueprint->getClassName(),
955 $lease_phid = $lease->getResourcePHID();
956 $resource_phid = $resource->getPHID();
958 if ($lease_phid !== $resource_phid) {
961 'Blueprint "%s" (of type "%s") is not properly implemented: it '.
962 'returned from "%s" with a lease acquired on the wrong resource.',
963 $blueprint->getBlueprintName(),
964 $blueprint->getClassName(),
970 /* -( Activating Leases )-------------------------------------------------- */
976 private function activateLease(DrydockLease
$lease) {
977 $resource = $lease->getResource();
980 pht('Trying to activate lease with no resource.'));
983 $resource_status = $resource->getStatus();
985 if ($resource_status == DrydockResourceStatus
::STATUS_PENDING
) {
986 throw new PhabricatorWorkerYieldException(15);
989 if ($resource_status != DrydockResourceStatus
::STATUS_ACTIVE
) {
990 throw new DrydockAcquiredBrokenResourceException(
992 'Trying to activate lease ("%s") on a resource ("%s") in '.
993 'the wrong status ("%s").',
995 $resource->getPHID(),
999 // NOTE: We can race resource destruction here. Between the time we
1000 // performed the read above and now, the resource might have closed, so
1001 // we may activate leases on dead resources. At least for now, this seems
1002 // fine: a resource dying right before we activate a lease on it should not
1003 // be distinguishable from a resource dying right after we activate a lease
1004 // on it. We end up with an active lease on a dead resource either way, and
1005 // can not prevent resources dying from lightning strikes.
1007 $blueprint = $resource->getBlueprint();
1008 $blueprint->activateLease($resource, $lease);
1009 $this->validateActivatedLease($blueprint, $resource, $lease);
1015 private function validateActivatedLease(
1016 DrydockBlueprint
$blueprint,
1017 DrydockResource
$resource,
1018 DrydockLease
$lease) {
1020 if (!$lease->isActivatedLease()) {
1021 throw new Exception(
1023 'Blueprint "%s" (of type "%s") is not properly implemented: it '.
1024 'returned from "%s" without activating a lease.',
1025 $blueprint->getBlueprintName(),
1026 $blueprint->getClassName(),
1033 /* -( Releasing Leases )--------------------------------------------------- */
1039 private function releaseLease(DrydockLease
$lease) {
1041 ->setStatus(DrydockLeaseStatus
::STATUS_RELEASED
)
1044 $lease->logEvent(DrydockLeaseReleasedLogType
::LOGCONST
);
1046 $resource = $lease->getResource();
1048 $blueprint = $resource->getBlueprint();
1049 $blueprint->didReleaseLease($resource, $lease);
1052 $this->destroyLease($lease);
1056 /* -( Breaking Leases )---------------------------------------------------- */
1062 protected function breakLease(DrydockLease
$lease, Exception
$ex) {
1063 switch ($lease->getStatus()) {
1064 case DrydockLeaseStatus
::STATUS_BROKEN
:
1065 case DrydockLeaseStatus
::STATUS_RELEASED
:
1066 case DrydockLeaseStatus
::STATUS_DESTROYED
:
1067 throw new PhutilProxyException(
1069 'Unexpected failure while destroying lease ("%s").',
1075 ->setStatus(DrydockLeaseStatus
::STATUS_BROKEN
)
1079 DrydockLeaseActivationFailureLogType
::LOGCONST
,
1081 'class' => get_class($ex),
1082 'message' => $ex->getMessage(),
1085 $lease->awakenTasks();
1090 'leasePHID' => $lease->getPHID(),
1093 'objectPHID' => $lease->getPHID(),
1096 throw new PhabricatorWorkerPermanentFailureException(
1098 'Permanent failure while activating lease ("%s"): %s',
1100 $ex->getMessage()));
1104 /* -( Destroying Leases )-------------------------------------------------- */
1110 private function destroyLease(DrydockLease
$lease) {
1111 $resource = $lease->getResource();
1114 $blueprint = $resource->getBlueprint();
1115 $blueprint->destroyLease($resource, $lease);
1118 DrydockSlotLock
::releaseLocks($lease->getPHID());
1121 ->setStatus(DrydockLeaseStatus
::STATUS_DESTROYED
)
1124 $lease->logEvent(DrydockLeaseDestroyedLogType
::LOGCONST
);
1126 $lease->awakenTasks();