Support Upstash Redis REST SDK in useResponseCache with Redis cache as store
Currently, useReponseCache offers a LRU and a Redis cache option.
The redis-cache relies on ioredis as seen here: https://github.com/dotansimha/envelop/blob/cdb32401bc385ca4d3503c4bc6b23ddb1a5909c6/packages/plugins/response-cache-redis/src/redis-cache.ts#L1
/**
* Redis instance
* @see Redis.Redis https://github.com/luin/ioredis
*/
redis: Redis.Redis;
And then any gets, sets, keys, or smember checks use the Redis client; for example:
// find the responseIds for the entity
const responseIds = await store.smembers(entity);
Describe the solution you'd like
Upstash is a serverless database service compatible with Redis® API.
They offer a REST API and a Javascript SDK: https://docs.upstash.com/redis/features/javascriptsdk
The advantage of this over a Redis client in the serverless world (where your GraphQL queries will be done in a Lambda like with RedwoodJS) is that it's less likely to run into connection limits. Other Redis offerings have 10, 20, 40 connections and base pricing on that where with Upstash the pricing is per usage.
Use upstash-redis in serverless functions if you expect high number of concurrent connections
Serverless functions scale up fast. This can cause some issues if you need persistent connections. REST based upstash-redis fits better in such cases as it does not require a TCP connection with its stateless design.
Also, the Rest client works well on the Edge in a Netlify or Vercel edge handler/function.
However, because the current cache implementation needs a client to invoke get etc, one cannot easily use the Upstash SDK:
For example (their sample code):
import { auth, set } from '@upstash/redis';
(async () => {
try {
auth('UPSTASH_REDIS_REST_URL', 'UPSTASH_REDIS_REST_TOKEN');
const { data, error } = await set('key', 'value');
if (error) throw error;
console.log(data);
// -> "OK"
} catch (error) {
console.error(error);
}
})();
Notice that here set is a method, but not like store.set() on the client.
Perhaps create another redis cache that uses Upstash specifically?
Would this be part of https://github.com/dotansimha/envelop/tree/main/packages/plugins/response-cache-redis/src or an entirely new plugin just for Upstash?
Other
Or, perhaps there is a way to modify the SDK such that there is a client that can be imported (here? https://github.com/upstash/upstash-redis/blob/master/src/index.ts) and then the plugin can have as is?
- Question: The REST API supports
pipelinebut not 100% certain if the SDK does.
Additional context
@dthyresson You can instantiate a new client as here
Pipeline will be supported by SDK soon (in ~2 weeks)
@dthyresson You can instantiate a new client as here
Pipeline will be supported by SDK soon (in ~2 weeks)
Thanks! I completely missed those docs.
I’ll keep a watch for pipeline support since with that I think can just drop in the Upstash client and be good to go. Currently the pipeline command is used.
I’ll keep this issue open as a reminder but I think it can become an issue to add documentation for using the Upstash Sdk instead.
Hi @enesakar I recently got back into trying out GraphQL response caching with the @upstash/redis client and am encountering the following error:
TypeError: Cannot use 'in' operator to search for 'ex' in PX
in @upstash/redis/script/pkg/commands/set.js:12:22
I Need to do some investigation, but currently looking at:
https://github.com/dotansimha/envelop/blob/4eaaf76d418cf56476d57c176ca876fff89a86b2/packages/plugins/response-cache-redis/src/redis-cache.ts#L71
Where set is used in a pipeline.
Also looking at: https://docs.upstash.com/redis/features/restapi#pipelining
Hey @dthyresson The @upstash/redis api is not compatible with ioredis, because we wanted to provide a nicer typescript experience, however it would be pretty easy to write a small adapter.
Judging from the readme example, I should probably just create another package that exports createUpstashCache(..)
So you would use it like this:
import { envelop } from '@envelop/core';
import { useResponseCache } from '@envelop/response-cache';
import { createUpstashCache } from '@envelop/response-cache-upstash';
import { Redis } from "@upstash/redis"
const cache = createUpstashCache(Redis.fromEnv());
const getEnveloped = envelop({
plugins: [
// ... other plugins ...
useResponseCache({ cache }),
],
});
Please let me know what you think and I'll implement it afterwards
@chronark Now that you mention the iodredis client in the package I was trying to use, this all makes so much sense why it wasn't working -- no idea why that didn't occur to me. :) I had a 🤦♂️ moment for sure.
A dedicated Upstash Redis client would be great and I know I'd want to use it.
Happy to help with implementation and testing as well.
Hey @dthyresson I've created a draft PR #1404 Maybe you can try and figure out why the tests are not working yet. I'll retry as well sometime this week.
Hey @dthyresson I've created a draft PR #1404 Maybe you can try and figure out why the tests are not working yet. I'll retry as well sometime this week.
Hi. I'll try too look too as well but Tim from the RedwoodJS community has offered to help as well; see: https://community.redwoodjs.com/t/guide-power-of-graphql-caching/2624/21?u=dthyresson
Hi @chronark, is upstash still planning on adding support for this or is it on the back-burner for now? We'd definitely be interested in using upstash if this was production-ready.
@akashkashyap a PR is here, currently it needs passing tests: https://github.com/n1ru4l/envelop/pull/1404#issuecomment-1346263662
Hey @akashkashyap yeah we definitely would like to make this happen
unfortunately I got completely stuck on making the tests work I'd appreciate a second set of eyes looking at it. I probably just made a stupid mistake