Skip to content
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

Caching for server side toggles #45

Open
Meemaw opened this issue Jun 10, 2023 · 9 comments
Open

Caching for server side toggles #45

Meemaw opened this issue Jun 10, 2023 · 9 comments
Labels
documentation Improvements or additions to documentation enhancement New feature or request examples

Comments

@Meemaw
Copy link

Meemaw commented Jun 10, 2023

Describe the feature request

It seems the current recommended approaches to get toggles with SSR/GSSP both use an un-cached fetch to the API. Since the definitions rarely change, I think it doesn't make much sense to fetch definitions for every request, but instead keep an unleash client instance around and re-fetch definitions every n seconds (in the background).

With this, we can then just do the toggles evaluation for each request.

Background

No response

Solution suggestions

Its fairly easy to implement something like this in user-land, but I think it would make sense to document/build this into the package itself for ease of usage.

@Meemaw Meemaw added the enhancement New feature or request label Jun 10, 2023
@Tymek
Copy link
Member

Tymek commented Jun 12, 2023

What we have right now

Server-side

App Router

You can do it with App Router server-side fetch cache, example here:
https://github.com/Unleash/unleash-client-nextjs/blob/main/example/src/app/app-page/page.tsx#L22

  const definitions = await getDefinitions({
    fetchOptions: {
      next: { revalidate: 15 },
    },
  });

Docs: https://nextjs.org/docs/app/building-your-application/data-fetching#caching-data

Pages Router

You can have an API endpoint that will fetch definitions, with cache-control (Docs). Then use this URL as source of definitions. As in middleware example.

Client-side

Unleash Edge

If you need to scale right now, we have Unleash Edge. It's written in Rust, crazy-performant implementation of a concept similar to Unleash Proxy. We have clients experimenting with setting it up on CloudFlare Edge Workers. It doesn't work on Vercel yet.

@Tymek
Copy link
Member

Tymek commented Jun 12, 2023

Plans

Client-side

I'll add an example of how to implement API route "proxying" for frontend API.

@Meemaw
Copy link
Author

Meemaw commented Jun 12, 2023

@Tymek thanks for the reply. I'm particularly interested in the Pages Router. While cache-control would help with the load on BE, its still a network roundtrip, which will add at least 50ms latency to the SSR render time (assuming its cached on CDN).

I was thinking more of a in-memory cache which would be instant and add no overhead at all.

@Tymek
Copy link
Member

Tymek commented Jun 12, 2023

You can use caching on SSR. (docs). Downside is that if you are returning definitions from there to the client, you will expose your configuration. You can filter toggles you're interested in I guess. Will including this in the library help? I'm hesitant because resolving feature toggles on frontend (running server-client on frontend) isn't something Unleash supported before Next.js SDK.

Correct me if I'm wrong, but I don't think it's possible to store something in-memory in a Serverless/Edge environment. I looked into using KV store, but definitions are too big for that.

@Meemaw
Copy link
Author

Meemaw commented Jun 12, 2023

You can use caching on SSR. (docs). Downside is that if you are returning definitions from there to the client, you will expose your configuration. You can filter toggles you're interested in I guess. Will including this in the library help? I'm hesitant because resolving feature toggles on frontend (running server-client on frontend) isn't something Unleash supported before Next.js SDK.

Correct me if I'm wrong, but I don't think it's possible to store something in-memory in a Serverless/Edge environment. I looked into using KV store, but definitions are too big for that.

By in memory I don't mean anything fansy, just storing things in a local variable. Not using Serveless/Edge, but I'm pretty sure you can do that. That being said, this would be more for the pages router, where you have a node server running for a long time.

@Tymek
Copy link
Member

Tymek commented Jun 12, 2023

I don't think that will run as expected on Cloudflare/Vercel etc. I'll experiment with it later this week. And again, if you have any user-land implementations, sharing it will help :)

Previous Next.js SDK experiment was using this approach (archived https://github.com/Unleash/next-unleash). I'll look into bringing it back.

@Meemaw
Copy link
Author

Meemaw commented Jun 12, 2023

I don't think that will run as expected on Cloudflare/Vercel etc. I'll experiment with it later this week. And again, if you have any user-land implementations, sharing it will help :)

Well, we are using unleash-client for now, but wanted to migrate to @unleash/nextjs. We are using a Unleash client instance, which will just fetch definitions every n seconds in the background. The client then exposes unleash.getFeatureToggleDefinitions() method which just returns these definitions from memory.

Something similar to this could work for us:

let definitions: Promise<ClientFeaturesResponse> | undefined;

export const getDefinitions = async (): Promise<ClientFeaturesResponse> => {
  if (!definitions) {
    definitions = loadDefinitions();
    setInterval(async () => {
      const updated = await loadDefinitions();
      definitions = Promise.resolve(updated);
    }, 15000);
  }
  return definitions;
};

@Tymek
Copy link
Member

Tymek commented Jun 12, 2023

Ok. Thank you for explaining 👍🏻
I'm in favor of wrapping cache(getDefinitions(...), ttl) in a functional style instead of OOP instances. It's flexible. An example use case with long-running Next.js server is definitely something I'd like to cover soon.

@Tymek Tymek added documentation Improvements or additions to documentation examples labels Jun 15, 2023
@mltsy
Copy link
Contributor

mltsy commented Feb 21, 2024

I had similar thoughts to @Meemaw when trying to switch to this package for the first time just recently. I guess the biggest question I have is: why doesn't @unleash/nextjs use the Node SDK (unleash-client) on the server side? It seems like that already has all of this stuff worked out, and this Next package could just pass in the applicable environment variables and wrap it up in a nice bow for the user, providing a long-lived server-side client for cases where we're not using serverless edge functions (which is the case for me).

I suppose maybe that wouldn't have made sense if the original motivation of this package was to support Serverless/Edge, but it's certainly worth supporting as an additional use-case, considering how simple it ought to be to just wrap up unleash-client (and since this package already requires unleash-client anyway).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request examples
Projects
Status: Todo
Development

No branches or pull requests

3 participants