I'm about to start a side project and I'd love to use TSS but for it to make sense I'd need to also be able to run cron jobs using TSS (otherwise the path to least resistance is react-router + fastify backend). What's the status of the server atm? Is it Vinxi still? Is this supported out of the box? Is it supported by the underlying infrastructure?
#Cronjob / Background task update
12 messages · Page 1 of 1 (latest)
Well really I'd just need a way to run something on server start (e.g. setup node-cron)
Hey, I can't find a solution either. Did you find one? I'm just trying to start the cronjob whenever the server starts up.
I think I found a solution. I implemented it this way, but I am not sure if it is secure or if it will work in production. While it works in development mode, I need to verify its behavior in a live environment.
In my vite.config.ts, I added the following:
plugins: [
devtools(),
viteTsConfigPaths({ projects: ['./tsconfig.json'] }),
tailwindcss(),
tanstackStart(),
nitro({
plugins: ['./src/cronjobs/autoInvoices.ts'],
}),
viteReact(),
],
optimizeDeps: {
exclude: ['@tanstack/start-server-core', '@tanstack/react-start'],
},
})```
Any feedback about this running in production? I'm facing a similar feature request in my TSS app. I'm needing to save PDF files to S3 + store a reference in my database after users batch print letters. Ideally, I could offload this to some sort of background task without blocking my server function.
Running cronjob in the node web server app is a bad idea.
In prod your app has multiple instances, so you would need somehow to sync it, using redis, some db, or any external persisted state. Otherwise all instances are goona do the same tasks. If you do not care that every instance will run your cron job then you can just use something like setInterval in your server entry point(you need to take into account redeploys, server crashes). You are mixing your web server requests handling with completely different case: cron job
Just use separate node app for this case, or some service. Dont mix both in the same node process
.
If your cron job specifically is coupled by logic to your tanstack server app you can do this:
Make a server route which executes your task, and then invoke it externally
Thanks for the explanation, that helped a lot!
My Docker Compose setup now includes a worker that starts automatically when the app boots. I’m running the cron job with tsx path.ts, so I guess that’s the right way to do it.
Would you mind sharing said Docker Compose setup? I’m interested to see how you have this set up.
Well, I'm pretty new to all this Docker stuff and the TanStack Start ecosystem, but I really like both! My current way of doing things might not be the only or the absolute best way, but it works perfectly for me. Here is my setup:
package.json scripts:
"dev": "vite dev --port 3000",
"build": "vite build",
"start": "node .output/server/index.mjs",
"start:prod": "node scripts/migrate.mjs && node .output/server/index.mjs",
"migrate:prod": "node scripts/migrate.mjs",
"start:worker": "tsx src/cronjobs/worker.ts",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:push": "drizzle-kit push",
"db:pull": "drizzle-kit pull",
"db:studio": "drizzle-kit studio"
}
Dockerfile:
WORKDIR /app
ARG APP_VERSION
ENV VITE_APP_VERSION=$APP_VERSION
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ARG APP_VERSION
ENV APP_VERSION=$APP_VERSION
ENV PORT=3000
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/.output ./.output
COPY --from=builder /app/drizzle ./drizzle
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/src ./src
EXPOSE 3000
CMD ["npm","run","start:prod"]
vite.config.ts:
(I had to add the nitroV2Plugin so that vite build still generates the .output folder with the standalone server!)
export default defineConfig({
plugins: [
devtools(),
viteTsConfigPaths({ projects: ['./tsconfig.json'] }),
tailwindcss(),
tanstackStart(),
nitroV2Plugin(),
viteReact(),
],
optimizeDeps: {
exclude: ['@tanstack/react-start', '@tanstack/start-server-core'],
},
})