I'm trialing PostHog for our SaaS app. For us, the lack of caching for feature flags are a total no-go. (We're currently canary-releasing a feature that requires a decide on every single page view.)
So I've added caching by extending the PostHog\Client and overriding fetchFeatureVariants.
<?php
use PostHog\Client;
use PostHog\HttpClient;
use Psr\Cache\CacheItemPoolInterface;
class CachingClient extends Client {
private const DEFAULT_EXPIRY_DURATION = 'PT5M'; // five minutes
private ?CacheItemPoolInterface $cache;
private \DateInterval $cacheExpiryInterval;
public function __construct(
string $apiKey,
array $options = [],
?HttpClient $httpClient = null,
string $personalAPIKey = null,
CacheItemPoolInterface $cache = null
) {
parent::__construct($apiKey, $options, $httpClient, $personalAPIKey);
$this->cache = $cache;
$this->cacheExpiryInterval = new \DateInterval($options['cacheDuration'] ?? self::DEFAULT_EXPIRY_DURATION);
}
public function fetchFeatureVariants(string $distinctId, array $groups = [], array $personProperties = [], array $groupProperties = []): array {
$callParent = fn() => parent::fetchFeatureVariants($distinctId, $groups, $personProperties, $groupProperties);
if (!$this->cache) {
return $callParent();
}
$query = substr(md5(json_encode([$groups, $personProperties, $groupProperties])), 0, 8); // yes, md5 is totally suitable here: it's fast and provides a good distribution
$cacheItem = $this->cache->getItem("FeatureFlags.dId=$distinctId.q=$query");
if ($cacheItem->isHit()) {
return $cacheItem->get();
}
$result = $callParent();
$this->cache->save(
$cacheItem
->expiresAfter($this->cacheExpiryInterval)
->set($result)
);
return $result;
}
}
I'd be happy to create a PR to add this to the base class.
I'm trialing PostHog for our SaaS app. For us, the lack of caching for feature flags are a total no-go. (We're currently canary-releasing a feature that requires a
decide
on every single page view.)So I've added caching by extending the
PostHog\Client
and overridingfetchFeatureVariants
.I'd be happy to create a PR to add this to the base class.