GraphCompose v1.2 is designed for request-scoped rendering. The library should not keep user CV text, addresses, emails, or generated PDF bytes in global state.
Create one DocumentSession per render request and close it with
try-with-resources:
try (DocumentSession document = GraphCompose.document().create()) {
document.pageFlow(page -> page
.module("Summary", module -> module.paragraph(summary))
.module("Skills", module -> module.bullets(skills)));
document.writePdf(responseOutputStream);
}DocumentSession is mutable and not thread-safe. Do not share one session
between requests or worker threads.
Use writePdf(OutputStream) when the next hop is already a stream:
- HTTP response bodies
- S3/blob/object-storage uploads
- file output opened by the application
- message or job pipelines that own their own stream
writePdf(...) writes the complete PDF to the supplied stream and does not
close it. The application owns flushing, closing, cancellation, and backpressure.
Use toPdfBytes() only when the caller truly needs a byte array. It is a
convenience wrapper over the streaming path and does not keep generated bytes in
the session.
buildPdf(Path) also uses the streaming path internally.
Use GraphCompose.document(path).guideLines(true) or
document.guideLines(true) only for local diagnostics, visual tests, and layout
debugging. Guide lines are a render-only overlay and do not change pagination or
layout snapshots. Production services should normally leave them disabled.
GraphCompose may share immutable font/style metrics globally because those keys do not contain user document text.
User text width measurements are request/session-local. They are bounded and
cleared when the session closes. Generated PDF bytes are not cached in
DocumentSession.
Application logging should follow the same rule: log ids, counts, timings, and error types, but do not log CV text, emails, phone numbers, addresses, links, or full generated output paths.
GraphCompose does not create an application-level worker pool. Production services should control concurrency outside the library:
- use a bounded executor or web-server worker pool
- apply queue limits and request timeouts
- stream output instead of collecting every PDF into memory
- apply tenant/user rate limits where needed
- treat failed renders as request failures, not reusable session state
This keeps the engine stateless across requests while still allowing safe internal reuse of font metrics and backend resources during a single render pass.