Feat: Add support for asynchronous fetching of feature toggles
markunl opened this issue · 10 comments
Is there an existing issue for this?
- I have searched the existing issues
Describe the new feature
Filing per discussion with @sighphyre
Currently the PHP SDK does not support the asynchronous fetching of feature toggles from the upstream Edge/Proxy/unleash instance.
This means clients see increased response times while the SDK syncs with the upstream Edge/Proxy/unleash instance, where cache TTL is 30 sec and is_enabled
method calls Unleash edge/instance after 30 sec have elapsed. This is especially relevant in scenarios where large payload responses are expected from Unleash (i.e large numbers of feature toggles and activation strategies).
Recent updates to PHP allow for asynchronous synchronization. Can support for this be implemented into the SDK? Let me know if any questions come up.
Is your feature request related to a problem? (optional)
No response
Describe alternatives you've considered (optional)
No response
Additional context (optional)
No response
I honestly don't think this is possible in a reasonable and universal way.
While php theoretically has support for async, it's not used asynchronously in most cases, this is the standard flow of a php app:
- you have some webserver (nginx, apache, caddy, whatever)
- that webserver either supports php directly (apache) or uses fpm (pretty much every serious webserver there is)
- when a request hits your webserver, it spawns a worker (or reuses an existing one but this is an implementation detail), the worker spawns a php process which handles the request and returns a html response, the process then exits
This all happens every request - php is usually used fully stateless.
To illustrate:
final class App {
public static bool $initialized = false;
}
var_dump(App::$initialized);
App::$initialized = true;
On every request it dumps false
because every request is its own process and no state is shared.
So given the constraints (every request = spawn a php process, process the request, the process dies), it's not possible to have a meaningful async implementation. Either way you would have to wait for the async completion before sending a response (if we made this "async" the only thing that changes is that the fetching of toggles theoretically happens at the end of the request instead of the mdidle, but you still have to wait before sending the response).
There are various async frameworks (swoole, React PHP and AMP PHP from the top of my head) but you need to structure your whole application around it because there's no event loop in php (that's basically what all those frameworks do - provide an event loop and provide alternative async functions for common sync php functions). Note that minority of applications work like that.
IMO we have these options:
- write integrations between this library and the mentioned frameworks (a lot of work, possibly duplicated logic in multiple libraries)
- add additional
isEnabledAsync()
and basically support both sync and async (the most work and a lot of added complexity for minuscule gains) - expose functionality to easily fetch the repository and store it in cache for use with external systems (the easiest way and also the de-facto standard way - the lack of async in php has historically been solved by using external systems like cron and job queues)
- do both 2. and 3.
Again, only a handful of applications support async, most are still the shared-nothing architecture I've been describing, I'm not sure options 1. and 2. are worth the time it will take to rewrite it.
Feel free to hit me on Slack if you want to chat about it a bit.
I don't believe this will solve the issues we hoped it would solve and it's also a major redesign of... well... everything. I'm going to close this and mark it as "won't do" but if someone ever has a need and a convincing argument for reconsidering it, please feel free to reopen