Skip to content

refactor: move quantity snapshotting to line engine#4749

Draft
turip wants to merge 1 commit into
feat/split-get-subscription-calls-reconstructedfrom
feat/move-quantity-snapshot-to-lineengine-reconstructed
Draft

refactor: move quantity snapshotting to line engine#4749
turip wants to merge 1 commit into
feat/split-get-subscription-calls-reconstructedfrom
feat/move-quantity-snapshot-to-lineengine-reconstructed

Conversation

@turip

@turip turip commented Jul 19, 2026

Copy link
Copy Markdown
Member

Summary

  • move quantity snapshotting into the legacy invoicing line engine
  • construct and inject one legacy line engine into billing and subscription sync
  • narrow the quantity snapshot dependency used by the invoice updater

Motivation

This aligns quantity snapshot ownership with the line engine and prepares the codebase for moving split-line-group handling out of the main billing path.

Stack

Reconstruction note

This draft reconstructs the original commit from #4746. The existing PRs and branches were intentionally left unchanged.

Validation

  • make test-nocache: 6,156 passed, 9 skipped on the original commit
  • fast Go lint: 0 issues on the original commit

Greptile Summary

This PR moves quantity snapshotting out of billingservice.Service and into billinglineengine.Engine, breaking a prior circular dependency where the service created an engine that called back into the service for snapshot logic. A single legacyBillingLineEngine instance is now constructed externally and injected into both the billing service and the subscription sync service.

  • InvoiceLineService is removed from the billing.Service interface and SnapshotLineQuantity becomes a method on *Engine instead; invoiceupdater.Updater is narrowed to depend on a new QuantitySnapshotter interface backed by the engine.
  • resolveFeatureMeters, featureMetersErrorWrapper, and all parallel-snapshot helpers are moved from openmeter/billing/service/quantitysnapshot.go into openmeter/billing/lineengine/quantitysnapshot.go; the engine now owns FeatureService, StreamingConnector, and MaxParallelQuantitySnapshots directly.
  • All test environments are updated to construct the engine separately and inject it.

Confidence Score: 4/5

The refactoring is mechanically straightforward — logic moved verbatim from the service to the engine, and the shared engine instance has no mutable state, making concurrent use safe.

The circular dependency is cleanly broken, all test environments are updated consistently, and the narrower QuantitySnapshotter interface in invoiceupdater is a clear improvement. The only thing worth cleaning up is a now-unreachable guard inside snapshotLineQuantitiesInParallel.

openmeter/billing/lineengine/quantitysnapshot.go — the dead workerCount guard; otherwise no file requires special attention.

Important Files Changed

Filename Overview
openmeter/billing/lineengine/quantitysnapshot.go Quantity snapshotting logic moved here from billingservice; includes new resolveFeatureMeters and featureMetersErrorWrapper. Dead guard (workerCount <= 0) is unreachable after Config.Validate enforces >= 1.
openmeter/billing/lineengine/engine.go Config expanded with FeatureService, StreamingConnector, MaxParallelQuantitySnapshots; QuantitySnapshotter field removed; all snapshot calls now go directly to Engine methods.
app/common/billing.go Adds NewLegacyBillingLineEngine factory and stores the engine in BillingRegistry; engine is properly shared with both billing service and subscription sync service.
openmeter/billing/service/service.go StreamingConnector and MaxParallelQuantitySnapshots removed from Config; LegacyBillingLineEngine injected directly instead of being created internally, eliminating the old circular dependency.
openmeter/billing/worker/subscriptionsync/service/reconciler/invoiceupdater/invoiceupdate.go Refactored to accept a QuantitySnapshotter interface (backed by *Engine) instead of the full billing.Service; New() now returns an error; Config.Validate() properly collects all field errors.
openmeter/billing/worker/subscriptionsync/service/reconciler/reconciler.go LegacyBillingLineEngine threaded through from top-level Config into invoiceupdater.New; error from invoiceupdater.New is properly handled.
openmeter/billing/service.go InvoiceLineService removed from billing.Service interface; SnapshotLineQuantity is no longer a public contract of the billing service.
test/billing/suite.go BaseSuite gains LegacyBillingLineEngine field; engine constructed separately with MaxParallelQuantitySnapshots=2 and shared with billing service.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller as Caller (billing / subsync)
    participant Factory as NewBillingRegistry / testenv
    participant Engine as billinglineengine.Engine
    participant BillingSvc as billingservice.Service
    participant Reconciler as reconciler.Service
    participant Updater as invoiceupdater.Updater

    Factory->>Engine: NewLegacyBillingLineEngine(adapter, rating, feature, streaming, cfg)
    Factory->>BillingSvc: "billingservice.New(Config{LegacyBillingLineEngine: engine})"
    Note over BillingSvc: RegisterLineEngine(engine)
    Factory->>Reconciler: "reconciler.New(Config{LegacyBillingLineEngine: engine})"
    Reconciler->>Updater: "invoiceupdater.New(Config{QuantitySnapshotter: engine})"

    Caller->>BillingSvc: OnCollectionCompleted(...)
    BillingSvc->>Engine: (via LineEngine registry) OnCollectionCompleted
    Engine->>Engine: SnapshotLineQuantities(invoice, lines)

    Caller->>Updater: ApplyPatches(...)
    Updater->>Engine: "SnapshotLineQuantity(SnapshotLineQuantityInput{invoice, line})"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller as Caller (billing / subsync)
    participant Factory as NewBillingRegistry / testenv
    participant Engine as billinglineengine.Engine
    participant BillingSvc as billingservice.Service
    participant Reconciler as reconciler.Service
    participant Updater as invoiceupdater.Updater

    Factory->>Engine: NewLegacyBillingLineEngine(adapter, rating, feature, streaming, cfg)
    Factory->>BillingSvc: "billingservice.New(Config{LegacyBillingLineEngine: engine})"
    Note over BillingSvc: RegisterLineEngine(engine)
    Factory->>Reconciler: "reconciler.New(Config{LegacyBillingLineEngine: engine})"
    Reconciler->>Updater: "invoiceupdater.New(Config{QuantitySnapshotter: engine})"

    Caller->>BillingSvc: OnCollectionCompleted(...)
    BillingSvc->>Engine: (via LineEngine registry) OnCollectionCompleted
    Engine->>Engine: SnapshotLineQuantities(invoice, lines)

    Caller->>Updater: ApplyPatches(...)
    Updater->>Engine: "SnapshotLineQuantity(SnapshotLineQuantityInput{invoice, line})"
Loading

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
openmeter/billing/lineengine/quantitysnapshot.go:145-149
The `workerCount <= 0` guard is unreachable: `Config.Validate()` already rejects any `MaxParallelQuantitySnapshots < 1`, so `e.maxParallelQuantitySnapshots` is guaranteed to be ≥ 1 by the time this method is called. The fallback can be safely removed.

```suggestion
func (e *Engine) snapshotLineQuantitiesInParallel(ctx context.Context, customer billing.InvoiceCustomer, lines billing.StandardLines, featureMeters feature.FeatureMeters) error {
	workerCount := e.maxParallelQuantitySnapshots
```

Reviews (1): Last reviewed commit: "refactor: move quantity snapshotting to ..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e1b80a96-8cd3-4c45-8ca3-53612056d083

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/move-quantity-snapshot-to-lineengine-reconstructed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment on lines +145 to 149
func (e *Engine) snapshotLineQuantitiesInParallel(ctx context.Context, customer billing.InvoiceCustomer, lines billing.StandardLines, featureMeters feature.FeatureMeters) error {
workerCount := e.maxParallelQuantitySnapshots
if workerCount <= 0 {
workerCount = 1
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 The workerCount <= 0 guard is unreachable: Config.Validate() already rejects any MaxParallelQuantitySnapshots < 1, so e.maxParallelQuantitySnapshots is guaranteed to be ≥ 1 by the time this method is called. The fallback can be safely removed.

Suggested change
func (e *Engine) snapshotLineQuantitiesInParallel(ctx context.Context, customer billing.InvoiceCustomer, lines billing.StandardLines, featureMeters feature.FeatureMeters) error {
workerCount := e.maxParallelQuantitySnapshots
if workerCount <= 0 {
workerCount = 1
}
func (e *Engine) snapshotLineQuantitiesInParallel(ctx context.Context, customer billing.InvoiceCustomer, lines billing.StandardLines, featureMeters feature.FeatureMeters) error {
workerCount := e.maxParallelQuantitySnapshots
Prompt To Fix With AI
This is a comment left during a code review.
Path: openmeter/billing/lineengine/quantitysnapshot.go
Line: 145-149

Comment:
The `workerCount <= 0` guard is unreachable: `Config.Validate()` already rejects any `MaxParallelQuantitySnapshots < 1`, so `e.maxParallelQuantitySnapshots` is guaranteed to be ≥ 1 by the time this method is called. The fallback can be safely removed.

```suggestion
func (e *Engine) snapshotLineQuantitiesInParallel(ctx context.Context, customer billing.InvoiceCustomer, lines billing.StandardLines, featureMeters feature.FeatureMeters) error {
	workerCount := e.maxParallelQuantitySnapshots
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Codex

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.

1 participant