fix(sink): require sink decoupling in the file sink impl itself - #26681
Draft
yuhao-su wants to merge 1 commit into
Draft
fix(sink): require sink decoupling in the file sink impl itself#26681yuhao-su wants to merge 1 commit into
yuhao-su wants to merge 1 commit into
Conversation
yuhao-su
marked this pull request as draft
August 16, 2026 03:04
The "file sinks must be decoupled" rule was a connector-name whitelist in the frontend catalog (`SinkDesc::is_file_sink`) listing fs/azblob/s3/webhdfs. It missed gcs and snowflake, although all six are `FileSink<_>` over the same OpenDAL writer: that writer commits a file only once its batching strategy is met and truncates the log store only then, so with `sink_decouple = false` a half-full batch leaves the checkpoint barrier untruncated and the whole streaming graph stalls. A gcs or snowflake sink created that way did exactly that. Move the rule to `is_sink_decouple` on `impl<S: OpendalSinkBackend> Sink for FileSink<S>`, where one generic impl covers every backend and any future one, and drop the whitelist plus its frontend special case. This is what the turbopuffer sink, which has the same requirement, already does. The error is now a sink config error instead of `NotSupported` with a HINT, so the remedy moves into the message text. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
yuhao-su
force-pushed
the
yuhao/fix-is-file-sink-gcs-snowflake
branch
from
August 16, 2026 03:20
66f4ca5 to
b47b799
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I hereby agree to the terms of the RisingWave Labs, Inc. Contributor License Agreement.
What's changed and what's your intention?
The rule "a file sink must run decoupled" was expressed as a connector-name whitelist in the frontend catalog —
SinkDesc::is_file_sink()listingfs/azblob/s3/webhdfs— and checked inStreamSink::create.for_all_sinks!registers sixFileSink<_>backends over the same OpenDAL writer, sogcsandsnowflakewere missing from that list.The rule is load-bearing.
OpenDalSinkWritercommits a file only once its batching strategy is met (10s rollover / 10240 rows) and truncates the log store only after a commit. On the non-decoupled in-memory log store, an untruncated checkpoint barrier parksBoundedInMemLogStoreReaderinAwaitingTruncate(next_item()returnspending()forever), so the sink never gets another chance to commit and the checkpoint never completes. Verified locally against aFileSink<_>sink created withset sink_decouple = false:FLUSHhangs indefinitely, unrelated DDL on the same cluster stops making progress, and nothing is ever written to the target; with decoupling enabled the same sink flushes in 0.1s and lands its files after the rollover.Rather than adding the two names to the list, this moves the rule to where the property lives:
is_sink_decoupleonimpl<S: OpendalSinkBackend> Sink for FileSink<S>. One generic impl covers all six backends and any backend added later, so the list can't drift out of sync again. The whitelist and its frontend special case are deleted. This mirrors the turbopuffer sink, which has the same requirement and already handles it this way.The frontend already dispatches
SinkType::is_sink_decouple(...)throughmatch_sink_name_str!a few lines above the special case, so no new machinery is needed.Behavior change
The error is now a sink config error rather than
ErrorCode::NotSupportedwith aHINT, so the remedy moves into the message text:Verification
test_requires_sink_decoupleinopendal_sink.rs(Default/Enableaccepted,Disablerejected) overfs,gcs,s3andsnowflake.e2e_test/sink/append_only_sink.sltextended from thes3case tos3+gcs+snowflake; passes locally. The check happens at planning time, before the connector'svalidate(), so no cloud credentials are involved.fssink is unaffected:FLUSHreturns immediately and a non-empty parquet file lands after the rollover../risedev cclean.Checklist
Documentation
gcsandsnowflakefile sinks can no longer be created withsink_decouple = false(they previously appeared to succeed and then stalled the streaming job). The error message for all file sinks changes as shown above.The check runs at plan time only, and the resulting log store type is persisted in the sink's plan, so this does not affect sinks that already exist: they keep the log store they were created with and are not re-validated on upgrade or recovery. A
gcsorsnowflakesink created earlier withsink_decouple = falsetherefore keeps its in-memory log store and its stalling behavior — it has to be dropped and recreated with decoupling enabled.🤖 Generated with Claude Code