mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 02:02:41 +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) {
|
||||
$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);
|
||||
}
|
||||
|
||||
protected function newConduitCallProxyClient(ConduitAPIRequest $request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract public function getAPIMethodName();
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,6 +51,10 @@ final class ConduitAPIRequest extends Phobject {
|
|||
return $this->user;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->getUser();
|
||||
}
|
||||
|
||||
public function setOAuthToken(
|
||||
PhabricatorOAuthServerAccessToken $oauth_token) {
|
||||
$this->oauthToken = $oauth_token;
|
||||
|
|
|
@ -85,6 +85,35 @@ abstract class DiffusionQueryConduitAPIMethod
|
|||
* should occur after @{method:getResult}, like formatting a timestamp.
|
||||
*/
|
||||
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');
|
||||
if ($identifier === null) {
|
||||
$identifier = $request->getValue('callsign');
|
||||
|
@ -92,7 +121,7 @@ abstract class DiffusionQueryConduitAPIMethod
|
|||
|
||||
$drequest = DiffusionRequest::newFromDictionary(
|
||||
array(
|
||||
'user' => $request->getUser(),
|
||||
'user' => $viewer,
|
||||
'repository' => $identifier,
|
||||
'branch' => $request->getValue('branch'),
|
||||
'path' => $request->getValue('path'),
|
||||
|
@ -106,46 +135,16 @@ abstract class DiffusionQueryConduitAPIMethod
|
|||
$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();
|
||||
$client = $repository->newConduitClient(
|
||||
$viewer,
|
||||
$is_cluster_request);
|
||||
if ($client) {
|
||||
// We're proxying, so just make an intracluster call.
|
||||
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);
|
||||
$client = $repository->newConduitClientForRequest($request);
|
||||
if ($client) {
|
||||
return $client;
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getResult(ConduitAPIRequest $request) {
|
||||
|
|
|
@ -2241,6 +2241,23 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
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() {
|
||||
$env = $_ENV;
|
||||
|
||||
|
|
Loading…
Reference in a new issue