Skip to content

Commit

Permalink
Add awareness of services a site should talk too
Browse files Browse the repository at this point in the history
  • Loading branch information
charrondev committed Sep 8, 2023
1 parent 2728f72 commit f52a801
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 95 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Contracts\Cache\CacheInterface;

$orchHttpClient = new OrchHttpClient("https://orch.vanilla.localhost", "access-token-here");
$siteProvider = new OrchSiteProvider($orchHttpClient, OrchCluster::REGION_AMS1, OrchCluster::NETWORK_PRODUCTION);
$siteProvider = new OrchSiteProvider($orchHttpClient, OrchCluster::REGION_AMS1_PROD1);

// It is highly recommended to set a user-agent for network requests.
$siteProvider->setUserAgent("my-service:1.0");
Expand All @@ -70,8 +70,8 @@ $cache = new MemcachedAdapter(/** Configuration here. */);

$siteProvider->setCache($cache);

# Region/network can be changed later
$siteProvider->setRegionAndNetwork(OrchCluster::REGION_YUL1, OrchCluster::NETWORK_DEVELOPMENT);
# Region can be changed later
$siteProvider->setRegionID(OrchCluster::REGION_YUL1_PROD1);
```

The orchestration provider needs to be configured with an authenticated `OrchHttpClient` and a region/network to load sites from.
Expand Down Expand Up @@ -159,5 +159,9 @@ function doSomethingWithSite(Site $site)
// Configs are cached on the `Garden\Sites\Site` instance
// You can clear them here.
$site->clearConfigCache();

// Check services hostnames the site should be using.
$baseUrl = $site->getQueueServiceBaseUrl();
$baseUrl = $site->getSearchServiceBaseUrl();
}
```
49 changes: 21 additions & 28 deletions src/Cluster.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,38 @@

namespace Garden\Sites;

use Garden\Sites\Exceptions\InvalidRegionException;
use Garden\Sites\Orch\OrchCluster;

/**
* Class representing a cluster of sites.
*/
class Cluster
{
public const REGION_YUL1_DEV1 = "yul1-dev1";
public const REGION_YUL1_PROD1 = "yul1-prod1";
public const REGION_AMS1_PROD1 = "ams1-prod1";
public const REGION_SJC1_PROD1 = "sjc1-prod1";
public const REGION_LOCALHOST = "localhost";
public const VALID_REGIONS = [
self::REGION_YUL1_DEV1,
self::REGION_YUL1_PROD1,
self::REGION_AMS1_PROD1,
self::REGION_SJC1_PROD1,
self::REGION_LOCALHOST,
];

private string $clusterID;
private string $region;
private string $network;
private string $regionID;

/**
* @param string $clusterID
* @param string $region
* @param string $network
* @param string $regionID One of {@link self::REGION*} constants.
*/
public function __construct(string $clusterID, string $region, string $network)
public function __construct(string $clusterID, string $regionID)
{
$this->clusterID = $clusterID;
$this->region = $region;
$this->network = $network;
$this->regionID = $regionID;
}

/**
Expand All @@ -42,30 +53,12 @@ public function getClusterID(): string
/**
* Get a string identifying the region that the cluster belongs to. This is normally an acronym for some geo-located datacenter.
*
* Examples:
* - mtl - {@link OrchCluster::REGION_YUL1}
* - sjc / sfo - {@link OrchCluster::REGION_SJC}
* - ams - {@link OrchCluster::REGION_AMS1}
*
* @return string
*/
public function getRegion(): string
{
return $this->region;
}

/**
* Get a string identifying the type of network the cluster runs on.
*
* Examples
* - production {@link OrchCluster::NETWORK_PRODUCTION}
* - development {@link OrchCluster::NETWORK_DEVELOPMENT}
* - localhost
* One of {@link self::VALID_REGIONS}
*
* @return string
*/
public function getNetwork(): string
public function getRegionID(): string
{
return $this->network;
return $this->regionID;
}
}
31 changes: 31 additions & 0 deletions src/Exceptions/InvalidRegionException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/**
* @copyright 2009-2023 Vanilla Forums Inc.
* @license Proprietary
*/

namespace Garden\Sites\Exceptions;

use Garden\Sites\Cluster;
use Garden\Utils\ContextException;

/**
* Exception thrown when we detect an invalid region.
*/
class InvalidRegionException extends ContextException
{
/**
* @param string $invalidRegion
*/
public function __construct(string $invalidRegion)
{
$message =
"Invalid region '$invalidRegion' detected. Valid regions are " .
implode(", ", Cluster::VALID_REGIONS) .
".";
parent::__construct($message, 500, [
"invalidRegion" => $invalidRegion,
"validRegions" => Cluster::VALID_REGIONS,
]);
}
}
2 changes: 1 addition & 1 deletion src/Local/LocalCluster.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ class LocalCluster extends Cluster

public function __construct(string $clusterID = self::DEFAULT_CLUSTER_ID)
{
parent::__construct($clusterID, "localhost", "localhost");
parent::__construct($clusterID, Cluster::REGION_LOCALHOST);
}
}
2 changes: 1 addition & 1 deletion src/Local/LocalSiteProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class LocalSiteProvider extends SiteProvider
*/
public function __construct(string $siteConfigFsBasePath)
{
parent::__construct("localhost", "localhost");
parent::__construct("localhost");
$this->siteConfigFsBasePath = $siteConfigFsBasePath;
}

Expand Down
14 changes: 3 additions & 11 deletions src/Orch/OrchCluster.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,20 @@
*/
class OrchCluster extends Cluster
{
public const REGION_YUL1 = "mtl";
public const REGION_AMS1 = "ams-1";
public const REGION_SJC = "sfo";

public const NETWORK_PRODUCTION = "production";
public const NETWORK_DEVELOPMENT = "development";

/** @var string Secret used in communication with the cluster. */
private string $secret;

/**
* Constructor.
*
* @param string $clusterID
* @param string $region
* @param string $network
* @param string $regionID
* @param string $secret
*/
public function __construct(string $clusterID, string $region, string $network, string $secret)
public function __construct(string $clusterID, string $regionID, string $secret)
{
$this->secret = $secret;
parent::__construct($clusterID, $region, $network);
parent::__construct($clusterID, $regionID);
}

/**
Expand Down
40 changes: 31 additions & 9 deletions src/Orch/OrchSiteProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

use Garden\Http\CurlHandler;
use Garden\Sites\Clients\OrchHttpClient;
use Garden\Sites\Cluster;
use Garden\Sites\Exceptions\ConfigLoadingException;
use Garden\Sites\SiteProvider;
use Garden\Sites\SiteRecord;
Expand All @@ -22,11 +23,14 @@ class OrchSiteProvider extends SiteProvider
private OrchHttpClient $orchHttpClient;

/**
* @param OrchHttpClient $orchHttpClient
* Constructor.
*
* @param OrchHttpClient $orchHttpClient A configured orch client.
* @param string $regionID One of the {@link Cluster::REGION_*} constants.
*/
public function __construct(OrchHttpClient $orchHttpClient, string $region, string $network)
public function __construct(OrchHttpClient $orchHttpClient, string $regionID)
{
parent::__construct($region, $network);
parent::__construct($regionID);
$this->orchHttpClient = $orchHttpClient;
}

Expand Down Expand Up @@ -80,12 +84,30 @@ public function loadAllClusters(): array

$result = [];
foreach ($apiClusters as $apiCluster) {
$cluster = new OrchCluster(
$apiCluster["ClusterID"],
$apiCluster["CloudZone"],
$apiCluster["Network"],
$apiCluster["ApiToken"],
);
switch ($apiCluster["CloudZone"]) {
case "sfo":
case "sjc":
$region = Cluster::REGION_SJC1_PROD1;
break;
case "ams":
case "ams-1":
$region = Cluster::REGION_AMS1_PROD1;
break;
case "mtl":
case "yul":
if ($apiCluster["Network"] === "production") {
$region = Cluster::REGION_YUL1_PROD1;
break;
} else {
$region = Cluster::REGION_YUL1_DEV1;
break;
}
default:
// Ignore this cluster.
continue 2;
}

$cluster = new OrchCluster($apiCluster["ClusterID"], $region, $apiCluster["ApiToken"]);
$result[$cluster->getClusterID()] = $cluster;
}

Expand Down
55 changes: 55 additions & 0 deletions src/Site.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Garden\Sites\Clients\SiteHttpClient;
use Garden\Sites\Exceptions\BadApiCredentialsException;
use Garden\Sites\Exceptions\ClusterNotFoundException;
use Garden\Sites\Exceptions\InvalidRegionException;
use Garden\Utils\ArrayUtils;

/**
Expand Down Expand Up @@ -182,4 +183,58 @@ public function jsonSerialize(): array
{
return $this->siteRecord->jsonSerialize();
}

/**
* Get the hostname of the proper search service to use for the cluster.
*
* @return string
*/
public function getQueueServiceBaseUrl(): string
{
$configOverride = $this->getConfigValueByKey("VanillaQueue.BaseUrl", null);
if (!empty($configOverride)) {
return $configOverride;
}

switch ($this->getCluster()->getRegionID()) {
case Cluster::REGION_LOCALHOST:
return "http://queue.vanilla.localhost";
case Cluster::REGION_YUL1_DEV1:
return "https://yul1-vanillaqueue-dev1.v-fabric.net";
case Cluster::REGION_YUL1_PROD1:
return "https://yul1-vanillaqueue-prod1.v-fabric.net";
case Cluster::REGION_AMS1_PROD1:
return "https://ams1-vanillaqueue-prod1.v-fabric.net";
case Cluster::REGION_SJC1_PROD1:
return "https://sjc1-vanillaqueue-prod1.v-fabric.net";
default:
throw new InvalidRegionException($this->getCluster()->getRegionID());
}
}

/**
* Get the hostname of the proper queue service to use for the cluster.
*
* @return string
*/
public function getSearchServiceBaseUrl(): string
{
$configOverride = $this->getConfigValueByKey("Inf.SearchApi.URL", null);
if (!empty($configOverride)) {
return $configOverride;
}

switch ($this->getCluster()->getRegionID()) {
case Cluster::REGION_LOCALHOST:
case Cluster::REGION_YUL1_DEV1: // This is temporary until we have a localhost version of the search api.
return "https://yul1-dev1-vanillasearch-api.v-fabric.net";
case Cluster::REGION_YUL1_PROD1:
case Cluster::REGION_SJC1_PROD1: // Temporarily using the YUL prod instance until https://higherlogic.atlassian.net/browse/PV-229 is completed.
return "https://yul1-vanillasearch-prod1-api.v-fabric.net";
case Cluster::REGION_AMS1_PROD1:
return "https://ms-vanilla-search-api-ams.v-fabric.net";
default:
throw new InvalidRegionException($this->getCluster()->getRegionID());
}
}
}
24 changes: 10 additions & 14 deletions src/SiteProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,33 +24,29 @@ abstract class SiteProvider
protected string $userAgent = "vanilla-sites-package";

/** @var string The region sites should be loaded from. */
protected string $region;

/** @var string The network sites should be loaded from. */
protected string $network;
protected string $regionID;

/**
* Constructor.
*
* @param string $regionID One of the {@link Cluster::REGION_*} constants
*/
public function __construct(string $region, string $network)
public function __construct(string $regionID)
{
$this->cache = new ArrayAdapter();
$this->region = $region;
$this->network = $network;
$this->regionID = $regionID;
}

/**
* Set the region and network we should be filtering too.
* Set the region we should be filtering too.
*
* @param string $region
* @param string $network
* @param string $regionID
*
* @return void
*/
public function setRegionAndNetwork(string $region, string $network): void
public function setRegionID(string $regionID): void
{
$this->region = $region;
$this->network = $network;
$this->regionID = $regionID;
}

/**
Expand Down Expand Up @@ -205,7 +201,7 @@ public function getClusters(): array
});

$filteredClusters = array_filter($allClusters, function (Cluster $cluster) {
return $cluster->getNetwork() === $this->network && $cluster->getRegion() === $this->region;
return $cluster->getRegionID() === $this->regionID;
});

return $filteredClusters;
Expand Down
Loading

0 comments on commit f52a801

Please sign in to comment.