Skip to content

feat(batch-export): local-volume backend so object storage is fully optional (#48) - #57

Merged
killme2008 merged 4 commits into
mainfrom
greptime-batch-export-local
Jul 1, 2026
Merged

feat(batch-export): local-volume backend so object storage is fully optional (#48)#57
killme2008 merged 4 commits into
mainfrom
greptime-batch-export-local

Conversation

@killme2008

@killme2008 killme2008 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Closes #48.

Batch exports were the last hard S3 dependency. This adds a local-file backend so a stock deployment needs no object storage at all.

What changed

  • Backend selector LANGFUSE_BATCH_EXPORT_STORAGE_BACKEND=s3|local + LANGFUSE_BATCH_EXPORT_LOCAL_PATH, mirroring the event/media backends, with boot fail-fast validation. The env-schema default is s3 so raw deployments keep upstream behavior; the bundled compose stacks (split + standalone) ship local so openfuse needs no bucket out of the box.
  • Worker (handleBatchExportJob): on the local backend, writes the export to a shared volume and mints a signed, time-limited download token instead of an S3 presigned URL. S3 path unchanged.
  • Signed token helper lives in @langfuse/shared so the worker mints and the web route verifies with the same secret (NEXTAUTH_SECRET ?? SALT). NEXTAUTH_SECRET is added to shared env and promoted to the shared compose env so web and worker resolve the same value.
  • Web download route /api/public/batch-exports/[batchExportId]/download: verifies the token, then re-validates the batchExport row (project scope, COMPLETED status, expiry) before streaming the file — strictly stronger than a presigned URL. Mirrors the local-media serving precedent.
  • Boot fail-fast on misconfig (review follow-up): when the local backend is selected, the worker requires NEXTAUTH_SECRET (so worker-signed tokens verify against web, which signs with NEXTAUTH_SECRET in production) and NEXTAUTH_URL in production (so minted links are reachable, not http://localhost:3000); the web runtime requires LANGFUSE_BATCH_EXPORT_LOCAL_PATH (the download route streams from it). Previously a split deployment could boot a runtime that silently produced unverifiable tokens, dead links, or 500'd every download.
  • Compose / Dockerfiles: shared langfuse_batch_export_data volume between web and worker (split + standalone stacks); backend defaults to local there. Dirs pre-created + chowned in the web/worker/standalone images.
  • Docs: removed the "batch exports still need an S3 bucket" caveat from README, docs/architecture.md, docs/deployment.md, docs/known-limitations.md, 07-deployment.md.

Security

The signed token is the presigned-URL equivalent (HMAC, time-limited, scoped to one export); the route additionally re-checks the DB row, so local downloads are not unauthenticated. Secret/URL/path misconfiguration now fails at boot rather than at download time.

Verification

  • typecheck (shared/worker/web), downloadToken unit tests 8/8, eslint on changed files, docker compose config -q on both compose files — all green.
  • Not yet verified: real-stack end-to-end (run an export with the local backend → click the email/UI link → download). Worth a manual smoke before merge.

…ptional

Batch exports were the last hard S3 dependency (issue #48). Add a
LANGFUSE_BATCH_EXPORT_STORAGE_BACKEND=s3|local selector mirroring the event /
media backends. On the local backend the worker writes the export to a shared
filesystem volume and mints a signed, time-limited download token; an
authenticated web route (/api/public/batch-exports/[id]/download) verifies the
token and re-validates the batchExport row (project scope, COMPLETED, expiry)
before streaming the file, replacing the S3 presigned URL.

The signing helper lives in shared so the worker can mint and the web route can
verify with the same secret (NEXTAUTH_SECRET ?? SALT); NEXTAUTH_SECRET is added
to shared env and promoted to the shared compose env so web and worker resolve
the same value. Compose files default the backend to local with a shared
langfuse_batch_export_data volume, so a stock deployment needs no object store.

Removes the 'batch exports still need an S3 bucket' caveat from the docs.
@killme2008
killme2008 force-pushed the greptime-batch-export-local branch from 5ed5d5b to 5315b1c Compare June 24, 2026 09:08
Local batch exports mint HMAC-signed download tokens and URLs in the
worker. Web verifies tokens with NEXTAUTH_SECRET (required in production)
and reaches links via NEXTAUTH_URL. The worker env schema validated
neither, so a split deployment could boot a worker that signs tokens with
a different secret (every download 400s) or mints unreachable
http://localhost:3000 links, both silently.

Require NEXTAUTH_SECRET whenever the local backend is selected, and
NEXTAUTH_URL in production, so misconfiguration fails at boot instead of
at download time.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

The web download route streams the export file from
LANGFUSE_BATCH_EXPORT_LOCAL_PATH. The web env left that path optional, so
a 'local' backend with no path booted fine but 500'd every download while
the worker still completed exports and stored signed URLs — easy to hit in
split deployments where worker and web envs diverge.

Validate it at boot like the worker does. t3-env exposes no cross-field
hook, so the refine reads the sibling backend from process.env directly.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Comment thread web/src/pages/api/public/batch-exports/[batchExportId]/download.ts
Comment thread web/src/pages/api/public/batch-exports/[batchExportId]/download.ts
Comment thread docs/deployment.md Outdated
…lume

Address PR #57 review:
- Encode Content-Disposition with an ASCII-only filename fallback plus a
  UTF-8 filename*, mirroring the trace download route, so a crafted export
  file name cannot break or inject the header.
- Document the langfuse_batch_export_data volume in docs/deployment.md
  (volumes table + shared-mount note).
@killme2008
killme2008 merged commit 78f584d into main Jul 1, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support local-volume batch exports (make object storage fully optional)

2 participants