-
-
Notifications
You must be signed in to change notification settings - Fork 27
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
Using redis-stack & lru makes static assets 404 #703
Comments
@bitttttten can you share the next.config file and the file that it's using the imports you mentioned? |
@mauroaccornero sure! // redis.mjs
import { CacheHandler } from '@neshca/cache-handler'
import createLruHandler from '@neshca/cache-handler/local-lru'
import createRedisHandler from '@neshca/cache-handler/redis-stack'
import invariant from 'invariant'
import { createClient } from 'redis'
const REDIS_URL = process.env.REDIS_URL
invariant(REDIS_URL, 'REDIS_URL is required inside redis.mjs')
CacheHandler.onCreation(async () => {
let client
try {
client = createClient({
url: REDIS_URL,
})
// Redis won't work without error handling. https://github.com/redis/node-redis?tab=readme-ov-file#events
client.on('error', error => {
if (process.env.NEXT_PRIVATE_DEBUG_CACHE === '1') {
// Use logging with caution in production. Redis will flood your logs. Hide it behind a flag.
console.error('[cache-handler-redis] Redis client error:', error)
}
})
} catch (error) {
console.warn('[cache-handler-redis] Failed to create Redis client:', error)
}
if (client) {
try {
console.info('[cache-handler-redis] Connecting Redis client...')
await client.connect()
console.info('[cache-handler-redis] Redis client connected.')
} catch (error) {
console.warn('[cache-handler-redis] Failed to connect Redis client:', error)
console.warn('[cache-handler-redis] Disconnecting the Redis client...')
client
.disconnect()
.then(() => {
console.info('[cache-handler-redis] Redis client disconnected.')
})
.catch(() => {
console.warn(
'[cache-handler-redis] Failed to quit the Redis client after failing to connect.',
)
})
}
}
/** @type {import("@neshca/cache-handler").Handler | null} */
let handler
if (client?.isReady) {
handler = await createRedisHandler({
client,
keyPrefix: `${process.env.PROJECT_NAME || 'next'}:`,
timeoutMs: 1000,
})
} else {
handler = createLruHandler()
console.warn(
'[cache-handler-redis] Falling back to LRU handler because Redis client is not available.',
)
}
return {
handlers: [handler],
}
})
export default CacheHandler Our next.config.mjs looks like import { generateConfig } from "next-configs/base.mjs";
import nextIntl from "next-intl/plugin";
import * as Sentry from "@sentry/nextjs";
import merge from "lodash.merge";
import bundleAnalyzer from '@next/bundle-analyzer'
import { getAssetPrefix, hasAssetPrefix } from '@/utils/asset-prefix.mjs'
function generateConfig(userConfig = {}) {
const assetPrefix = hasAssetPrefix() ? getAssetPrefix() : undefined;
/**
* @type {NextConfig}
*/
const base = {
logging: {
fetches: {
fullUrl: true,
},
},
assetPrefix,
reactStrictMode: true,
typescript: {
ignoreBuildErrors: true,
},
eslint: {
ignoreDuringBuilds: true,
},
trailingSlash: true,
transpilePackages: [],
experimental: {
instrumentationHook: true,
optimizePackageImports: [
"@radix-ui/primitive",
"@radix-ui/react-avatar",
"@radix-ui/react-tooltip",
"@radix-ui/react-dialog",
"@radix-ui/react-popover",
"@radix-ui/react-select",
"@radix-ui/react-slider",
"@radix-ui/react-switch",
"@radix-ui/react-radio-group",
"@radix-ui/react-toolbar",
"@radix-ui/react-tooltip",
],
},
};
const cacheHandler = {
cacheHandler: require.resolve("./redis.mjs"),
cacheMaxMemorySize: 0,
};
const config = merge(base, cacheHandler, userConfig);
if (process.env.ANALYZE === "true") {
const withBundleAnalyzer = bundleAnalyzer({
openAnalyzer: true,
});
return withBundleAnalyzer(config);
}
return config;
}
const base = generateConfig({
images: {
loader: "custom",
loaderFile: "./custom-image-loader.ts",
remotePatterns: [],
},
async rewrites() {
return {
beforeFiles: [
// some redirects
],
};
},
async headers() {
return [
{
// adds some custom headers
},
];
},
});
const withNextIntl = nextIntl("./i18n.ts");
const sentryWebpackPluginOptions = {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
silent: true,
hideSourceMaps: false,
disableLogger: true,
sourceMaps: {
disable: true,
},
unstable_sentryWebpackPluginOptions: {
applicationKey: "*****",
},
};
export default Sentry.withSentryConfig(
withNextIntl(base),
sentryWebpackPluginOptions
); Happy to share more info if you need. |
@bitttttten thanks for the files. if you run the build command on your machine do you get any error?
It's weird to me the require.resolve used like that in a mjs file. For a mjs file to use require I normally do something like this:
if you want you can check this example I suggest to avoid using the cache handler when not in production, you can do that in your next.config file
another suggestion is to not use redis cache when building, you can add an if before the try catch in your redis.mjs file
maybe try to run the build and start command on your machine to see if you get any error |
Ah sorry I am stripping a bunch of things out as they are sensitive to the project. Indeed we have require resolve already: import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
const cacheHandler = {
cacheHandler:
process.env.REDIS_HOSTNAME && process.env.REDIS_PASSWORD
? require.resolve('./cache-handler-redis.mjs')
: require.resolve('./cache-handler-noop.js'),
cacheMaxMemorySize: 0,
} and now we have this. I looked into disabling the handler in the production build phase already like // redis.mjs
class CacheHandler {
///
}
const cache = new Map()
class CacheHandlerMemory {
async get(key) {
return cache.get(key)
}
async set(key, data, ctx) {
cache.set(key, {
value: data,
lastModified: Date.now(),
tags: ctx.tags,
})
}
async revalidateTag(tag) {
for (let [key, value] of cache) {
if (value.tags.includes(tag)) {
cache.delete(key)
}
}
}
}
const loadInMemory = process.env.NEXT_PHASE === 'phase-production-build'
console.log(`Cache handler: ${loadInMemory ? 'Memory' : 'Redis'}`)
export default loadInMemory ? CacheHandlerMemory : CacheHandler And still no bueno yet. I don't get any errors, the nextjs app compiles, it just fails to load the css when starting. If there is an error, it's getting swallowed somewhere.. |
Maybe you can try to replace CacheHandlerMemory with undefined. |
We tried the example cacheHandler from the repo and running in the same problem. |
@bitttttten hello! Does your app live in a monorepo? |
yes! |
I've had issues with assets in a monorepo in the past. Please ensure that the problem isn't caused by misconfigured tracing. Refer to this Next.js documentation on |
oh interesting, that was actually my next thing to attempt to look into! when i manage to implement the outputFileTracingRoot and see it's affect, i will let you know. thanks |
@bitttttten hello! Did the |
I am running into similar issues, is there a recommended fix or the known root-cause of why this happens? I am also seeing scenarios where redeploying changes seem to make the pages go 404 and those never get revalidated unless, I manually revalidate each page. |
@whizzzkid hi! Which Next.js Router do you use in your project? |
@mauroaccornero the link to your example is no longer available: |
@JSONRice it's public now |
Am facing this issue as well, when the application is redeployed, it is using the previous cache version of a static page which reference assets from the previous deployment. Is there away to ensure the cache is purged or is some configuration missing on my end? |
Brief Description of the Bug
When using
We see that our static assets like JS and CSS files sometimes 404.
So not all, but some.
Severity
Maybe Major?
Frequency of Occurrence
Always
Environment:
It happens on CircleCI and local on M3 and M1.
Dependencies and Versions
[email protected]
@neshca/[email protected]
Attempted Solutions or Workarounds
None so far, we removed the package and continuing using our own redis cache handler.
Impact of the Bug
Critical, we cannot get Next.JS assets loaded.
Additional context
None, but happy to provide more!
The text was updated successfully, but these errors were encountered: