-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Cache] add integration with Messenger to allow computing cached values in a worker #30572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. I really like this feature.
Could you show a code example how I would use it.
I’m also trying to figure out how I can work around the limitation..
07f2817
to
bac41f9
Compare
@Nyholm thanks for having a look :) To test this, you need to configure a pool with the framework:
cache:
pools:
test.cache:
messenger_bus: message_bus
messenger:
transports:
amqp: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
'Symfony\Component\Cache\Messenger\Message': amqp BTW, this shows another area where Messenger needs to improve: how should a bundle provide configuration for this Message-to-transport mapping out of the box? ping @sroze @ogizanagi @weaverryan. Then e.g. in a controller: /**
* @Route("/test", name="test")
*/
public function index(CacheInterface $testCache)
{
$value = $testCache->get('foo', [$this, 'compute']);
return $this->render('test/index.html.twig', [
'value' => $value,
]);
}
public function compute(ItemInterface $item)
{
$item->expiresAfter(5);
sleep(1);
return sprintf('#%06X', mt_rand(0, 0xFFFFFF));
} Runnig the dev weberver: |
4020350
to
4f69bb1
Compare
See https://github.com/nicolas-grekas/cache-bus for a running example. |
Looks like a great idea 😍 |
4f69bb1
to
85ac760
Compare
What's the status of this PR? I feel everyone concerned is at the EU hackathon, could be a great opportunity to merge :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's black magic
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
Outdated
Show resolved
Hide resolved
Can you rebase and perhaps answers the few questions? |
I would love to see this merged/updated to be merged! I think that is a great addition for performances |
03614f8
to
178ce8d
Compare
I'm adding tests, that should be ok in a few hours. |
d067d1b
to
5880f9b
Compare
I rebased the PR and added unit tests. It works \o/ I also verified on the demo app I built last year, all works as expected 🎉 Status: needs review |
Stunning idea! |
5880f9b
to
e173ddc
Compare
@nicolas-grekas Can you fix the tests? |
c2f5b44
to
0de9af9
Compare
0de9af9
to
6c0911f
Compare
Thank you @nicolas-grekas. |
This PR needs and for now embeds #30334. See 2nd commit.Using the new
CacheInterface
enables probabilistic early expiration by default. This means that from time to time, items are elected as early-expired while they are still fresh (see Wikipedia for details).This PR adds a new
early_expiration_message_bus
option when configuring cache pools. When this option is set, cache pools are configured to send those early-expired items on a Messenger bus, then serve the current value immediately, while the updated value is computed in a worker in the background.CacheInterface::get($key, $callback)
accepts any callable, but sending any callable on a bus is not possible (e.g. aClosure
cannot be serialized). To bypass this constraint, this feature works only with callables in the form[$service, 'publicMethod']
, where$service
is any public or reversible service.This constraint is a serious one: this $service must compute a value when knowing only its key. This means keys should embed enough information for this to happen. I think that's not that hard - and we may find ways to provide additional context in the future.
At least the goal is worth it: in theory, this strategy allows achieving a 100% hit ratio even when invalidation-by-expiration is used.
There are two things one needs to do to enable this behavior: