mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
Lift Diffusion Conduit call proxying to the root level of Conduit
Summary: Ref T13552. Some Diffusion conduit calls may only be served by a node which hosts a working copy on disk, so they're proxied if received by a different node. This capability is currently bound tightly to "DiffusionRequest", which is a bundle of context parameters used by some Diffusion calls. However, call proxying is not fundamentally a Diffusion behavior. I want to perform proxying on a "*.search" call which does not use the "DiffusionRequest" parameter bundle. Lift proxying to the root level of Conduit. Test Plan: Browsed diffusion in a clusterized repsository. Maniphest Tasks: T13552 Differential Revision: https://secure.phabricator.com/D21442
This commit is contained in:
parent
367cd28927
commit
a745055813
4 changed files with 70 additions and 38 deletions
|
@ -120,9 +120,21 @@ abstract class ConduitAPIMethod
|
||||||
public function executeMethod(ConduitAPIRequest $request) {
|
public function executeMethod(ConduitAPIRequest $request) {
|
||||||
$this->setViewer($request->getUser());
|
$this->setViewer($request->getUser());
|
||||||
|
|
||||||
|
$client = $this->newConduitCallProxyClient($request);
|
||||||
|
if ($client) {
|
||||||
|
// We're proxying, so just make an intracluster call.
|
||||||
|
return $client->callMethodSynchronous(
|
||||||
|
$this->getAPIMethodName(),
|
||||||
|
$request->getAllParameters());
|
||||||
|
}
|
||||||
|
|
||||||
return $this->execute($request);
|
return $this->execute($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newConduitCallProxyClient(ConduitAPIRequest $request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
abstract public function getAPIMethodName();
|
abstract public function getAPIMethodName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -51,6 +51,10 @@ final class ConduitAPIRequest extends Phobject {
|
||||||
return $this->user;
|
return $this->user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getViewer() {
|
||||||
|
return $this->getUser();
|
||||||
|
}
|
||||||
|
|
||||||
public function setOAuthToken(
|
public function setOAuthToken(
|
||||||
PhabricatorOAuthServerAccessToken $oauth_token) {
|
PhabricatorOAuthServerAccessToken $oauth_token) {
|
||||||
$this->oauthToken = $oauth_token;
|
$this->oauthToken = $oauth_token;
|
||||||
|
|
|
@ -85,6 +85,35 @@ abstract class DiffusionQueryConduitAPIMethod
|
||||||
* should occur after @{method:getResult}, like formatting a timestamp.
|
* should occur after @{method:getResult}, like formatting a timestamp.
|
||||||
*/
|
*/
|
||||||
final protected function execute(ConduitAPIRequest $request) {
|
final protected function execute(ConduitAPIRequest $request) {
|
||||||
|
$drequest = $this->getDiffusionRequest();
|
||||||
|
|
||||||
|
// We pass this flag on to prevent proxying of any other Conduit calls
|
||||||
|
// which we need to make in order to respond to this one. Although we
|
||||||
|
// could safely proxy them, we take a big performance hit in the common
|
||||||
|
// case, and doing more proxying wouldn't exercise any additional code so
|
||||||
|
// we wouldn't gain a testability/predictability benefit.
|
||||||
|
$is_cluster_request = $request->getIsClusterRequest();
|
||||||
|
$drequest->setIsClusterRequest($is_cluster_request);
|
||||||
|
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
$repository = $drequest->getRepository();
|
||||||
|
|
||||||
|
// TODO: Allow web UI queries opt out of this if they don't care about
|
||||||
|
// fetching the most up-to-date data? Synchronization can be slow, and a
|
||||||
|
// lot of web reads are probably fine if they're a few seconds out of
|
||||||
|
// date.
|
||||||
|
id(new DiffusionRepositoryClusterEngine())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setRepository($repository)
|
||||||
|
->synchronizeWorkingCopyBeforeRead();
|
||||||
|
|
||||||
|
return $this->getResult($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function newConduitCallProxyClient(ConduitAPIRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
$identifier = $request->getValue('repository');
|
$identifier = $request->getValue('repository');
|
||||||
if ($identifier === null) {
|
if ($identifier === null) {
|
||||||
$identifier = $request->getValue('callsign');
|
$identifier = $request->getValue('callsign');
|
||||||
|
@ -92,7 +121,7 @@ abstract class DiffusionQueryConduitAPIMethod
|
||||||
|
|
||||||
$drequest = DiffusionRequest::newFromDictionary(
|
$drequest = DiffusionRequest::newFromDictionary(
|
||||||
array(
|
array(
|
||||||
'user' => $request->getUser(),
|
'user' => $viewer,
|
||||||
'repository' => $identifier,
|
'repository' => $identifier,
|
||||||
'branch' => $request->getValue('branch'),
|
'branch' => $request->getValue('branch'),
|
||||||
'path' => $request->getValue('path'),
|
'path' => $request->getValue('path'),
|
||||||
|
@ -106,46 +135,16 @@ abstract class DiffusionQueryConduitAPIMethod
|
||||||
$identifier));
|
$identifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out whether we're going to handle this request on this device,
|
|
||||||
// or proxy it to another node in the cluster.
|
|
||||||
|
|
||||||
// If this is a cluster request and we need to proxy, we'll explode here
|
|
||||||
// to prevent infinite recursion.
|
|
||||||
|
|
||||||
$is_cluster_request = $request->getIsClusterRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$repository = $drequest->getRepository();
|
$repository = $drequest->getRepository();
|
||||||
$client = $repository->newConduitClient(
|
|
||||||
$viewer,
|
$client = $repository->newConduitClientForRequest($request);
|
||||||
$is_cluster_request);
|
|
||||||
if ($client) {
|
if ($client) {
|
||||||
// We're proxying, so just make an intracluster call.
|
return $client;
|
||||||
return $client->callMethodSynchronous(
|
|
||||||
$this->getAPIMethodName(),
|
|
||||||
$request->getAllParameters());
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// We pass this flag on to prevent proxying of any other Conduit calls
|
|
||||||
// which we need to make in order to respond to this one. Although we
|
|
||||||
// could safely proxy them, we take a big performance hit in the common
|
|
||||||
// case, and doing more proxying wouldn't exercise any additional code so
|
|
||||||
// we wouldn't gain a testability/predictability benefit.
|
|
||||||
$drequest->setIsClusterRequest($is_cluster_request);
|
|
||||||
|
|
||||||
$this->setDiffusionRequest($drequest);
|
|
||||||
|
|
||||||
// TODO: Allow web UI queries opt out of this if they don't care about
|
|
||||||
// fetching the most up-to-date data? Synchronization can be slow, and a
|
|
||||||
// lot of web reads are probably fine if they're a few seconds out of
|
|
||||||
// date.
|
|
||||||
id(new DiffusionRepositoryClusterEngine())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->setRepository($repository)
|
|
||||||
->synchronizeWorkingCopyBeforeRead();
|
|
||||||
|
|
||||||
return $this->getResult($request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->setDiffusionRequest($drequest);
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getResult(ConduitAPIRequest $request) {
|
protected function getResult(ConduitAPIRequest $request) {
|
||||||
|
|
|
@ -2241,6 +2241,23 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
return $client;
|
return $client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newConduitClientForRequest(ConduitAPIRequest $request) {
|
||||||
|
// Figure out whether we're going to handle this request on this device,
|
||||||
|
// or proxy it to another node in the cluster.
|
||||||
|
|
||||||
|
// If this is a cluster request and we need to proxy, we'll explode here
|
||||||
|
// to prevent infinite recursion.
|
||||||
|
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
$is_cluster_request = $request->getIsClusterRequest();
|
||||||
|
|
||||||
|
$client = $this->newConduitClient(
|
||||||
|
$viewer,
|
||||||
|
$is_cluster_request);
|
||||||
|
|
||||||
|
return $client;
|
||||||
|
}
|
||||||
|
|
||||||
public function getPassthroughEnvironmentalVariables() {
|
public function getPassthroughEnvironmentalVariables() {
|
||||||
$env = $_ENV;
|
$env = $_ENV;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue