Sergey Makagonov
03/30/2026, 4:34 PM1:00pm VPJ1 pushes purchase_count = 3
1:10pm RT update: purchase_count = 4
1:15pm RT update: purchase_count = 5
1:30pm RT update: purchase_count = 6
1:35pm VPJ2 pushes, but batch data lags by 15min: purchase_count = 5
As VPJ2's new version is being built, RT events from 110 130 are also being applied to it. But DCR resolves conflicts by timestamp:
• Batch sets purchase_count = 5 (with timestamp 1:35pm)
• RT event from 1:30pm (purchase_count = 6) has an earlier timestamp
• Timestamp-based resolution: batch wins. Value regresses to 5.
So far, my understanding is that achieving good consistency with Batch + RT updates is possible only if RT updates separate set of fields through write-compute.
Am I missing something? I put up a doc on Venice Hybrid store considerations as a reference.
cc @Hubert Puszklewicz @Amre ShakimZac Policzer
03/30/2026, 4:37 PMZac Policzer
03/30/2026, 4:39 PMSergey Makagonov
03/30/2026, 4:42 PMSo a qq, what does good consistency mean in this case? For version 2, you just don't want to serve a read such that it shows up as purchase_count =5 if you already consumed up to that point on version 1?Good consistency here means: if a key's value was updated to 6 by RT at 1:30pm, and a batch push happens at 1:35pm with stale data (5), the store should not regress to 5. The most recent correct value should win regardless of which pipeline wrote it.
Sergey Makagonov
03/30/2026, 4:45 PMIn the store config there are a few knobs you can turn w.r.t. hybrid store configuration. You can set a minimum time lag threshhold before a version is available for serving. So let's say 15mins is too much, but you're ok with maybe 5m of lag. You can configure Venice such that a version is not marked as 'ready' unless it's within 5 minutes of lag relative to the head of the RTThat makes sense for controlling when the version goes online. But I think the issue is one step deeper: even after the version has caught up to RT head and is ready to serve, doesn't DCR resolve in favor of the batch value? The batch data carries a later timestamp (VPJ submission time) than the RT events it's overwriting, so even though the RT events are replayed into the new version, the batch value wins the timestamp comparison
Sergey Makagonov
03/30/2026, 4:47 PMZac Policzer
03/30/2026, 4:48 PMZac Policzer
03/30/2026, 4:48 PMZac Policzer
03/30/2026, 4:50 PMOn top of that, the freshness of batch data depends on upstream dependencies too. Our batch is a dbt model in Snowflake that depends on other models, so the actual data staleness can be much larger than just the VPJ runtime. Same problem you'd have with any Presto/Spark batch pipeline where the output depends on a chain of upstream jobs, each with their own scheduling delays and potential retries.I think I understand this. The tl;dr though is that nearline data is NEWER data then what's in the batch right?
Sergey Makagonov
03/30/2026, 4:51 PMSergey Makagonov
03/30/2026, 4:56 PMKoorous Vargha
03/30/2026, 5:11 PMSergey Makagonov
03/30/2026, 5:14 PMJust to make sure I'm understanding correctly, if the timestamp of the RT event > batch event you want the RT event to win DCR?no, it's opposite - RT even can have more recent data, even though it's timestamp is 5-10min earlier than Batch kafka event.
Koorous Vargha
03/30/2026, 5:14 PMSergey Makagonov
03/30/2026, 5:16 PMBATCH_WRITE_LOSES(0) // RT always wins over batch
USE_START_OF_PUSH_TIMESTAMP(1) // Batch uses SOP timestamp, RT wins if its timestamp is higher
USE_PER_RECORD_LOGICAL_TIMESTAMP(2) // Full per-record timestamp comparisonKoorous Vargha
03/30/2026, 5:17 PMKoorous Vargha
03/30/2026, 5:23 PMBATCH_WRITE_LOSES .
Is it not working as expected?Zac Policzer
03/30/2026, 5:37 PMSergey Makagonov
03/30/2026, 5:37 PMZac Policzer
03/30/2026, 5:38 PMZac Policzer
03/30/2026, 5:39 PMSergey Makagonov
03/30/2026, 5:45 PMSergey Makagonov
03/30/2026, 5:46 PMSergey Makagonov
03/30/2026, 8:22 PMFelix GV
03/31/2026, 5:06 PMWhen Batch and RT update disjoint sets of fields - then things are clean, no interference between the two.This use case is what Write Compute's Partial Update is meant to solve. I would definitely recommend using that operation in the RT pipeline.
The confusion happens for the fields that are updated from both - and so far it looks like it's not a good thing to do at all.In theory that should be fine as long as the timestamps are properly set (which admittedly is easier said than done). Note that by default the RT pipeline will use the producer process’ clock as the TS, but this can be overridden with a logical time of your own if you have access to one… again, easier said than done, but if the logical TS is wired in correctly, then the system should work fine even in the case of processing lag, or duplicate data, etc, which are always possible scenarios in stream processing…
Sergey Makagonov
03/31/2026, 5:32 PMwhich admittedly is easier said than doneyeah, it can be very nuanced, but I assume if updates are possible on same fields from an RT job, than whatever is pushed from the batch should not be too far from the source, making it feasible to populate a proper logical timestamp. Another place where things can get interesting is if we have incremental pushes + RT updates, because both are going to the _rt topic. So, for example, setup like "do full push daily, incremental push hourly, and support RT updates for freshness in between incremental pushes" can be tricky to do. In that sense, having one of "full push daily + incremental hourly" or "full push daily and RT updates through Flink" may be cleaner.
Felix GV
03/31/2026, 5:34 PMFelix GV
03/31/2026, 5:35 PMSergey Makagonov
03/31/2026, 5:38 PMdelete from inc push was missing maybethat's interesting. Feel like it should be just about the writing tombstone rows with NULL value. If there are any limitations to the incremental logic, would be great to know about those (I don't see anything in the documentation https://venicedb.org/user-guide/write-apis/batch-push/?h=incremental#incremental-push)
Zac Policzer
03/31/2026, 8:33 PM