1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-02 18:08:26 +01:00

Move the "container updated" message for Buildables that build Diffs outside of the transaction

Summary:
Ref T13216. See PHI970. Ref T13054. See some discussion in T13216.

When a Harbormaster Buildable object is first created for a Diff, it has no `containerPHID` since the revision has not yet been created.

We later (after creating a revision) send the Buildable a message telling it that we've added a container and it should re-link the container object.

Currently, we send this message in `applyExternalEffects()`, which runs inside the Differential transaction. If Harbormaster races quickly enough, it can read the `Diff` object before the transaction commits, and not see the container update.

Add a `didCommitTransaction()` callback after the transactions commit, then move the message code there instead.

Test Plan:
  - See T13216 for substantial evidence that this change is on the right track.
  - Before change: added `sleep(15)`, reproduced the issue reliably.
  - After change: unable to reproduce issue even with `sleep(15)` (the `containerPHID` always populates correctly).

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13216, T13054

Differential Revision: https://secure.phabricator.com/D19807
This commit is contained in:
epriestley 2018-11-14 15:54:04 -08:00
parent 44c32839a6
commit b2e91d2205
5 changed files with 47 additions and 12 deletions

View file

@ -57,6 +57,12 @@ final class DifferentialRevisionUpdateTransaction
// Harbormaster. See discussion in T8650. // Harbormaster. See discussion in T8650.
$diff->setRevisionID($object->getID()); $diff->setRevisionID($object->getID());
$diff->save(); $diff->save();
}
public function didCommitTransaction($object, $value) {
$editor = $this->getEditor();
$diff = $editor->requireDiff($value);
$omnipotent = PhabricatorUser::getOmnipotentUser();
// If there are any outstanding buildables for this diff, tell // If there are any outstanding buildables for this diff, tell
// Harbormaster that their containers need to be updated. This is // Harbormaster that their containers need to be updated. This is
@ -64,7 +70,7 @@ final class DifferentialRevisionUpdateTransaction
// and unit results. // and unit results.
$buildables = id(new HarbormasterBuildableQuery()) $buildables = id(new HarbormasterBuildableQuery())
->setViewer(PhabricatorUser::getOmnipotentUser()) ->setViewer($omnipotent)
->withManualBuildables(false) ->withManualBuildables(false)
->withBuildablePHIDs(array($diff->getPHID())) ->withBuildablePHIDs(array($diff->getPHID()))
->execute(); ->execute();

View file

@ -869,6 +869,24 @@ abstract class PhabricatorApplicationTransactionEditor
return $xactions; return $xactions;
} }
final protected function didCommitTransactions(
PhabricatorLiskDAO $object,
array $xactions) {
foreach ($xactions as $xaction) {
$type = $xaction->getTransactionType();
$xtype = $this->getModularTransactionType($type);
if (!$xtype) {
continue;
}
$xtype = clone $xtype;
$xtype->setStorage($xaction);
$xtype->didCommitTransaction($object, $xaction->getNewValue());
}
}
public function setContentSource(PhabricatorContentSource $content_source) { public function setContentSource(PhabricatorContentSource $content_source) {
$this->contentSource = $content_source; $this->contentSource = $content_source;
return $this; return $this;
@ -1106,6 +1124,9 @@ abstract class PhabricatorApplicationTransactionEditor
$object->saveTransaction(); $object->saveTransaction();
$transaction_open = false; $transaction_open = false;
} }
$this->didCommitTransactions($object, $xactions);
} catch (Exception $ex) { } catch (Exception $ex) {
if ($read_locking) { if ($read_locking) {
$object->endReadLocking(); $object->endReadLocking();

View file

@ -35,6 +35,10 @@ abstract class PhabricatorModularTransactionType
return; return;
} }
public function didCommitTransaction($object, $value) {
return;
}
public function getTransactionHasEffect($object, $old, $new) { public function getTransactionHasEffect($object, $old, $new) {
return ($old !== $new); return ($old !== $new);
} }

View file

@ -103,26 +103,26 @@ abstract class PhabricatorWorkerTaskQuery
return $this->formatWhereClause($conn, $where); return $this->formatWhereClause($conn, $where);
} }
protected function buildOrderClause(AphrontDatabaseConnection $conn_r) { protected function buildOrderClause(AphrontDatabaseConnection $conn) {
// NOTE: The garbage collector executes this query with a date constraint, // NOTE: The garbage collector executes this query with a date constraint,
// and the query is inefficient if we don't use the same key for ordering. // and the query is inefficient if we don't use the same key for ordering.
// See T9808 for discussion. // See T9808 for discussion.
if ($this->dateCreatedBefore) { if ($this->dateCreatedBefore) {
return qsprintf($conn_r, 'ORDER BY dateCreated DESC, id DESC'); return qsprintf($conn, 'ORDER BY dateCreated DESC, id DESC');
} else if ($this->dateModifiedSince) { } else if ($this->dateModifiedSince) {
return qsprintf($conn_r, 'ORDER BY dateModified DESC, id DESC'); return qsprintf($conn, 'ORDER BY dateModified DESC, id DESC');
} else { } else {
return qsprintf($conn_r, 'ORDER BY id DESC'); return qsprintf($conn, 'ORDER BY id DESC');
} }
} }
protected function buildLimitClause(AphrontDatabaseConnection $conn_r) { protected function buildLimitClause(AphrontDatabaseConnection $conn) {
$clause = '';
if ($this->limit) { if ($this->limit) {
$clause = qsprintf($conn_r, 'LIMIT %d', $this->limit); return qsprintf($conn, 'LIMIT %d', $this->limit);
} else {
return qsprintf($conn, '');
} }
return $clause;
} }
} }

View file

@ -145,19 +145,23 @@ final class PhabricatorWorkerTriggerQuery
return $triggers; return $triggers;
} }
protected function buildJoinClause(AphrontDatabaseConnection $conn_r) { protected function buildJoinClause(AphrontDatabaseConnection $conn) {
$joins = array(); $joins = array();
if (($this->nextEpochMin !== null) || if (($this->nextEpochMin !== null) ||
($this->nextEpochMax !== null) || ($this->nextEpochMax !== null) ||
($this->order == self::ORDER_EXECUTION)) { ($this->order == self::ORDER_EXECUTION)) {
$joins[] = qsprintf( $joins[] = qsprintf(
$conn_r, $conn,
'JOIN %T e ON e.triggerID = t.id', 'JOIN %T e ON e.triggerID = t.id',
id(new PhabricatorWorkerTriggerEvent())->getTableName()); id(new PhabricatorWorkerTriggerEvent())->getTableName());
} }
return implode(' ', $joins); if ($joins) {
return qsprintf($conn, '%LJ', $joins);
} else {
return qsprintf($conn, '');
}
} }
protected function buildWhereClause(AphrontDatabaseConnection $conn) { protected function buildWhereClause(AphrontDatabaseConnection $conn) {