When using `cache.get` and `cache.set` within the same route handler, a `Reply was already sent` error occurs
5t111111 opened this issue · 1 comments
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the issue has not already been raised
Issue
Sorry, I'm not sure if this is a bug or if I'm using it incorrectly.
I am trying to use fastify-caching to cache the results of a process that fetches data from an external API within a route handler.
The mechanism is simple:
- if there is valid cache data, it should be returned.
- if not, the data should be fetched from the external API and then cached.
To achieve this, I tried to implement caching by nesting cache.get and cache.set callbacks, as shown below. However, I always get a Reply was already sent error when there is no cached data. Also, the response being sent is not the externalApiResponseJson, but an empty response.
import Fastify from "fastify";
import fastifyCaching from "@fastify/caching";
const fastify = Fastify({
logger: true,
});
fastify.register(fastifyCaching, {
privacy: fastifyCaching.privacy.PRIVATE,
});
fastify.get("/", async function (request, reply) {
fastify.cache.get(
"extData",
// Make this callback async to use await in it.
async (err, result) => {
if (!err && result && result.item) {
reply.send(result.item);
} else {
const externalApiResponse = await fetch(
"https://jsonplaceholder.typicode.com/todos/1"
);
const externalApiResponseJson = await externalApiResponse.json();
fastify.cache.set("extData", externalApiResponseJson, 60000, (err) => {
if (err) {
throw err;
}
// ** Every time you send reply here, "Reply was already sent" error occurs. **
reply.send(externalApiResponseJson);
});
}
}
);
});
fastify.listen({ port: 3000 }, function (err, address) {
if (err) {
fastify.log.error(err);
process.exit(1);
}
});This code is also a minimal reproduction of the issue, and the actual project involves more complex processing, but the basic structure remains the same.
I looked through the documentation and test codes of fastify-caching, but I could not find an example that uses cache.get and cache.set within the same route handler, so I am unsure of the correct usage. I would appreciate any guidance.
Node version: 20.18.0
package.json
{
"name": "fastify-caching-issue",
"main": "index.js",
"dependencies": {
"@fastify/caching": "^9.0.1",
"fastify": "^5.0.0"
}
}In my situation, the issue was resolved by explicitly using the useAwait option. I believe the problem was likely caused by the callback function of cache.set not being designed to work with async / await, so I think my usage was incorrect.
Below is the updated code:
import Fastify from "fastify";
import fastifyCaching from "@fastify/caching";
import abstractCache from "abstract-cache";
const fastify = Fastify({
logger: true,
});
const abcache = abstractCache({
useAwait: true,
});
fastify.register(fastifyCaching, {
privacy: fastifyCaching.privacy.PRIVATE,
cache: abcache,
});
fastify.get("/", async function (request, reply) {
const extData = await fastify.cache.get("extData");
if (extData) {
return reply.send(extData.item);
}
const externalApiResponse = await fetch(
"https://jsonplaceholder.typicode.com/todos/1"
);
const externalApiResponseJson = await externalApiResponse.json();
fastify.cache.set("extData", externalApiResponseJson, 10000);
reply.send(externalApiResponseJson);
});
fastify.listen({ port: 3000 }, function (err, address) {
if (err) {
fastify.log.error(err);
process.exit(1);
}
});