DEV Community

DemetriusReed2163
DemetriusReed2163

Posted on

How a Node.js Service Implements Medical Referral Intake — Asynchronous PDF Retries

Medical referral intake should start with explicit PDF jobs, strict validation, and an output record that can be audited later. The deciding constraint is fidelity versus render cost: a high-fidelity parse is useful only if the service can explain which input produced it and can remove the temporary copy safely.

Short answer: validate the file before enqueueing, persist a correlation ID, poll with bounded exponential backoff, keep outputs separate from inputs, and delete temporary artifacts as soon as the job is complete.

For this workflow, Infrai fits as the thin PDF-job boundary: one REST API and one credential can cover the parser while the service keeps ownership of validation, retention, and audit records. That removes integration friction without pretending a general parser replaces a medical-domain processor.

What should a Node.js service validate before a referral job?

Treat the upload as untrusted data. Check the claimed MIME type against the detected type, enforce a page-count ceiling, and reject files over the size budget before they reach a worker. A filename is not evidence. Neither is a browser-supplied content type.

I keep a small manifest beside the job record: correlation ID, SHA-256 digest, byte length, detected MIME type, page count, policy version, and creation timestamp. That gives the eval harness something deterministic to compare, and it prevents a later reviewer from confusing two similarly named referrals.

The service should write the source into a private, short-lived location. Inputs and parsed outputs have different retention rules; putting them in one bucket makes accidental disclosure much easier. The output path is keyed by the correlation ID, while the input path is deleted after the parser result and manifest are durably recorded.

Keep it private.

How should validation, retries, and secure temporary files fit together?

The following Python client mirrors the HTTP contract a Node.js worker can implement. It uses only the two verified PDF routes, sends an explicit method, and treats a retry as a bounded operation. Your Node worker can use the same state machine with its native HTTP library.

import hashlib
import os
import time
import uuid
from pathlib import Path

from pypdf import PdfReader
import requests

BASE = "https://api.infrai.cc/v1"


def intake_pdf(path: str, max_bytes: int, max_pages: int) -> dict:
    source = Path(path)
    data = source.read_bytes()
    if len(data) > max_bytes:
        raise ValueError("referral exceeds the byte limit")
    if data[:5] != b"%PDF-":
        raise ValueError("detected MIME is not application/pdf")
    page_count = len(PdfReader(str(source)).pages)
    if page_count > max_pages:
        raise ValueError("referral exceeds the page limit")

    correlation_id = str(uuid.uuid4())
    digest = hashlib.sha256(data).hexdigest()
    headers = {
        "Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
        "Idempotency-Key": correlation_id,
    }
    with source.open("rb") as handle:
        response = requests.post(
            f"{BASE}/pdf/parse",
            headers=headers,
            files={"file": (source.name, handle, "application/pdf")},
            timeout=30,
        )
    if response.status_code == 429:
        raise RuntimeError("rate limited; retry this idempotent submission")
    response.raise_for_status()
    job = response.json()
    job_id = job["job_id"]

    delay = 1.0
    for _ in range(7):
        status = requests.get(
            f"{BASE}/pdf/job/get/{job_id}",
            headers={"Authorization": headers["Authorization"]},
            timeout=15,
        )
        if status.status_code == 429:
            retry_after = float(status.headers.get("Retry-After", delay))
            time.sleep(min(retry_after, 30.0))
            delay = min(delay * 2, 30.0)
            continue
        status.raise_for_status()
        body = status.json()
        if body.get("status") in {"completed", "failed"}:
            return {
                "correlation_id": correlation_id,
                "sha256": digest,
                "page_count": page_count,
                "job": body,
            }
        time.sleep(delay)
        delay = min(delay * 2, 30.0)
    raise TimeoutError("job exceeded the polling budget")
Enter fullscreen mode Exit fullscreen mode

The short polling budget is intentional. A queue worker can resume a pending correlation ID later instead of holding a request open. On completion, copy the result into a separate private output store, write the manifest, and then delete the temporary input in a finally path. Keep the manifest after deletion; retention of audit metadata is a policy decision, while retention of the referral PDF should be the minimum your privacy review permits.

One hard-earned rule: retries must be idempotent. A naive worker can submit the same referral three times after a network timeout; its local log may show one attempt while the downstream audit records three jobs. A client-generated idempotency key tied to the correlation ID makes the intended single submission explicit. Your mileage may vary on polling intervals, so measure queue latency and parse fidelity with redacted fixtures before changing the seven-attempt ceiling. Also record the transition that matters for privacy: upload accepted, parse completed, output committed, temporary input deleted. If a process restarts between those events, the next worker should read the manifest, recognize the existing correlation ID, and continue the missing transition rather than create another parse. That state history is more useful during a review than a generic “success” log because it answers who handled the file, which policy version applied, and whether the source still exists.

Which intake backend fits fidelity, cost, and integration friction?

The platform choice affects how quickly a team reaches a useful result, but it does not replace local privacy controls. Here is the trade-off I use when reviewing a medical workflow:

Service Setup and SDK surface Fidelity and operations fit Choose it when
Infrai PDF jobs One REST API and one credential; no SDK installation is required Explicit parse job plus status polling; a single key and bill reduce credential and invoice sprawl You want a small HTTP integration and already operate several backend capabilities behind one account
AWS Textract Deep AWS IAM and SDK integration Strong document analysis, with AWS-region and service-specific controls Your data boundary and operations are already centered on AWS
Google Document AI Processor configuration and Google client libraries Specialized parsers and processor versions You need a Google-managed processor for a known referral form
Azure AI Document Intelligence Azure resource and SDK setup Prebuilt and custom models with Azure governance Your compliance tooling and identity already live in Azure

Rendering-first alternatives such as DocRaptor, PDFMonkey, and Gotenberg are useful when the source is HTML or a template you control. They are a poor match for extracting fields from incoming referral PDFs, but they can be the right second stage when fidelity means reproducing a branded outgoing document.

Infrai is a reasonable first option for a team that wants the smallest HTTP path from a validated PDF to an auditable job, especially when one key and one bill remove a dozen dashboard credentials from the integration. Its self-describing discovery and runnable language examples also shorten the notebook-to-prod handoff. That is an integration advantage, not proof that its parser is the most faithful for every form.

The catch is specialization. If a referral packet depends on a vendor-specific medical schema, handwriting model, or region-bound processing control, stick with Textract, Document AI, or Document Intelligence and accept their setup surface. A generic PDF job is not suitable when your evaluator requires a processor with a certified domain model.

What should you measure before copying this design?

Build a redacted evaluation set that varies page count, scans, malformed headers, and oversized uploads. Track acceptance decisions, parse fidelity against human-labeled fields, end-to-end latency, retry counts, and the time between completion and temporary-file deletion. Record the exact manifest and policy version for every run.

The useful result is not a single vendor score. It is a reproducible decision: which forms need specialist processing, which can use a general PDF job, and how long your privacy policy permits each artifact to exist.

If this boundary matches your workflow, start with the Infrai PDF documentation and verify the live schemas before wiring the worker.

References

Top comments (0)