Getting data from sources with different precedence - CoR?

I’m looking through some of our services, and I see code that looks something like this:

$data = $sharedCache->get($key);

if ($data) {
    return $data;
} elseif ($data = $localCache($key)) {
    $sharedCache->set($key, $data);
    return $data;
} else {
    $data = getFromSource($key);
    $localCache->set($key, $data);
    $sharedCache->set($key, $data);
    return $data;
}

Hopefully it’s fairly clear what’s going on, and also why it needs to be cleaned up. I have an idea in my head, which sounds a lot like Chain of Responsibility to me, but I wanted to pick some brains and see if I’m on the right track or not.

So we have three possible sources for this data with increasing chances of having the data that I need, but also with increasing latency and increasing API costs:

  1. Local cache on server
  2. Shared cache available to entire cluster
  3. Remote service which is the System of Record

So I’m going to rewrite this so that I can essentially chain these together and implement a common interface. I’m thinking something like this:

$localCache = new Cache($localParams);
$sharedCache = new Cache($sharedParams);
$remoteSource = new DataOrigin($originParams);

$localCache->onFailure($sharedCache);
$sharedCache->onFailure($remoteSource);

return $localCache->get($key);

Here we’re setting a fallback object to handle failure in the first object, ie if we can’t find the data in the local cache then it falls back to the shared cache, and if that also doesn’t have the data then it will fall back to the SoR which should always have the right information available. Because all three will implement the same interface they will all have the same get($key) method available to them in order to request the data from their fallback. DataOrigin won’t have a fallback object defined through its onFailure() method so would throw an exception if it can’t find the data still and we’ll handle that in an appropriate place.

Each part of the chain will then return the data back up the chain where it can be cached and eventually returned to the original calling function and can then be handled.

So, this looks and sounds like Chain of Responsibility to me. The question is whether you guys think that this is a good solution, and if you have any better suggestions

I see two possible problems in your solution, comparing it with the old one:

  • You change the order in the chain of responsibility, from shared-local-remote to local-shared-remote. Are you sure that won’t be a problem?

  • In the code you post, if there’s a failure in local and in shared, the remote value doesn’t make it to local? I’m sure this is just a quick draft, and maybe I’m missing something, but thought I’d point it out :wink:

Just two practical observations. Can’t help you with your question.

[quote=“guido2004, post:2, topic:201625”]
You change the order in the chain of responsibility, from shared-local-remote to local-shared-remote. Are you sure that won’t be a problem?
[/quote]That was a mistake on my part :smile:

[quote=“guido2004, post:2, topic:201625”]
In the code you post, if there’s a failure in local and in shared, the remote value doesn’t make it to local? I’m sure this is just a quick draft, and maybe I’m missing something, but thought I’d point it out
[/quote]Not sure how this would be any different to the current implementation. If we’re handling errors and exceptions properly then there’s no problem, and all that they’re doing is returning the value from the next link in the chain anyway (caching as they go). They don’t do much in that respect that could go dramatically wrong :smile:

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.