pub struct HttpSink { /* private fields */ }sink-http only.Expand description
An HTTP sink that sends records to an HTTP endpoint.
Implementations§
Source§impl HttpSink
impl HttpSink
Sourcepub fn new(config: HttpSinkConfig) -> HttpSink
pub fn new(config: HttpSinkConfig) -> HttpSink
Create a new HTTP sink from the given configuration.
Sourcepub fn with_auth_provider(self, provider: Arc<dyn AuthProvider>) -> HttpSink
pub fn with_auth_provider(self, provider: Arc<dyn AuthProvider>) -> HttpSink
Attach a shared AuthProvider. When set,
the provider supplies the credential for every request (taking
precedence over inline auth), so several sinks can share one token with
single-flight refresh. Used by the CLI to resolve auth: { ref }, and
by library callers who construct one provider and inject it into many
sinks.
Trait Implementations§
Source§impl Sink for HttpSink
impl Sink for HttpSink
Source§fn check<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 CheckContext,
) -> Pin<Box<dyn Future<Output = Result<CheckReport, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
HttpSink: 'async_trait,
fn check<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 CheckContext,
) -> Pin<Box<dyn Future<Output = Result<CheckReport, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
HttpSink: 'async_trait,
Non-mutating preflight probe (probe name "network").
Issues a lightweight HEAD request to the configured endpoint over the
existing reqwest client. We only care that the host is reachable — that
DNS, TCP, TLS and the server all work — so any HTTP response (2xx,
4xx including 405 Method Not Allowed, or 5xx) counts as a pass. Only a
transport/connection error (no response at all) is a failure.
Source§fn write_batch_partial<'life0, 'life1, 'async_trait>(
&'life0 self,
records: &'life1 [Value],
) -> Pin<Box<dyn Future<Output = Result<Vec<Result<(), FaucetError>>, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
HttpSink: 'async_trait,
fn write_batch_partial<'life0, 'life1, 'async_trait>(
&'life0 self,
records: &'life1 [Value],
) -> Pin<Box<dyn Future<Output = Result<Vec<Result<(), FaucetError>>, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
HttpSink: 'async_trait,
Report per-row outcomes so the DLQ router dead-letters only the records that genuinely failed.
In Individual mode every record is an independent POST, so each
record’s success/failure is attributable: we attempt all of them
(unlike write_batch, whose ? short-circuits on the first failure)
and return one Ok/Err per record. Without this
override the default impl would surface the first error as an outer
Err, and under on_batch_error: dlq_all the pipeline would route the
entire batch to the DLQ — duplicating the already-delivered rows
against a non-idempotent endpoint (#146 M14).
In Array mode the page is POSTed chunk-by-chunk (batch_size
slices), so forward progress is not atomic across the whole page —
each chunk is a separate, independently-committed array POST. The
override is therefore chunk-aware rather than all-or-nothing: it
iterates the chunks itself and POSTs each array; a row whose chunk was
delivered is reported Ok(()), while the rows of the first failing
chunk (and every not-yet-sent chunk after it) are reported Err.
This is the fix for the duplicate-data bug (F15 / audit #264): the old
implementation delegated to the all-or-nothing write_batch, so a late
chunk failure surfaced the whole page as an outer Err. Under
on_batch_error: dlq_all the router then dead-lettered every row —
including rows from earlier chunks already successfully delivered to the
live endpoint — producing silent downstream duplicates. By reporting
per-row outcomes, an already-delivered row is never marked failed and
so can never land in the DLQ.
Within a single failed chunk a single array POST cannot attribute the
failure to specific rows, so all rows of that chunk are reported Err
(acceptable — none of them were delivered). When the first chunk
fails (nothing has been delivered yet) the override preserves the
original all-or-nothing contract and surfaces an outer Err, so the
router’s on_batch_error policy (abort vs. dead-letter) still applies to
a wholly-undelivered page exactly as before.
Source§fn config_schema(&self) -> Value
fn config_schema(&self) -> Value
Source§fn dataset_uri(&self) -> String
fn dataset_uri(&self) -> String
Source§fn write_batch<'life0, 'life1, 'async_trait>(
&'life0 self,
records: &'life1 [Value],
) -> Pin<Box<dyn Future<Output = Result<usize, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
HttpSink: 'async_trait,
fn write_batch<'life0, 'life1, 'async_trait>(
&'life0 self,
records: &'life1 [Value],
) -> Pin<Box<dyn Future<Output = Result<usize, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
HttpSink: 'async_trait,
Source§fn flush<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn flush<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Source§fn supports_idempotent_writes(&self) -> bool
fn supports_idempotent_writes(&self) -> bool
false (at-least-once only). Read moreSource§fn sink_guarantee(&self) -> SinkGuarantee
fn sink_guarantee(&self) -> SinkGuarantee
SinkGuarantee. Read moreSource§fn dedups_by_key(&self) -> bool
fn dedups_by_key(&self) -> bool
write_mode: upsert (or delete) with a non-empty key, so
re-applying a record with the same key converges instead of
duplicating. Default: false. Read moreSource§fn supported_write_modes(&self) -> &'static [WriteMode]
fn supported_write_modes(&self) -> &'static [WriteMode]
WriteMode::Upsert /
WriteMode::Delete. The CLI rejects a
configured mode that is not in this set at config-load time.Source§fn current_schema<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn current_schema<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
infer_schema-shaped object
({"type":"object","properties":{ <col>: <type-fragment>, … }}), or
None for a schemaless sink or a target that does not exist yet. Read moreSource§fn supports_schema_evolution(&self) -> bool
fn supports_schema_evolution(&self) -> bool
evolve_schema. Default: false. The CLI rejects
on_drift: evolve against a sink that returns false at config-load.Source§fn evolve_schema<'life0, 'life1, 'async_trait>(
&'life0 self,
evolution: &'life1 SchemaEvolution,
) -> Pin<Box<dyn Future<Output = Result<(), FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn evolve_schema<'life0, 'life1, 'async_trait>(
&'life0 self,
evolution: &'life1 SchemaEvolution,
) -> Pin<Box<dyn Future<Output = Result<(), FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
ADD COLUMN IF NOT EXISTS semantics) so concurrent runs converge. Read moreSource§fn write_batch_idempotent<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
records: &'life1 [Value],
scope: &'life2 str,
token: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<usize, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
fn write_batch_idempotent<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
records: &'life1 [Value],
scope: &'life2 str,
token: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<usize, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
Source§fn last_committed_token<'life0, 'life1, 'async_trait>(
&'life0 self,
scope: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn last_committed_token<'life0, 'life1, 'async_trait>(
&'life0 self,
scope: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, FaucetError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
scope, or None if this sink has
never committed under that scope. Default: None.Source§fn connector_name(&self) -> &'static str
fn connector_name(&self) -> &'static str
connector label on metrics and the
connector attribute on spans. See Source::connector_name.Auto Trait Implementations§
impl !RefUnwindSafe for HttpSink
impl !UnwindSafe for HttpSink
impl Freeze for HttpSink
impl Send for HttpSink
impl Sync for HttpSink
impl Unpin for HttpSink
impl UnsafeUnpin for HttpSink
Blanket Implementations§
Source§impl<T> AsAny for T
impl<T> AsAny for T
Source§fn any_ref(&self) -> &(dyn Any + Sync + Send + 'static)
fn any_ref(&self) -> &(dyn Any + Sync + Send + 'static)
dyn Any reference to the object: Read moreSource§fn as_any(self: Arc<T>) -> Arc<dyn Any + Sync + Send> ⓘ
fn as_any(self: Arc<T>) -> Arc<dyn Any + Sync + Send> ⓘ
Arc<dyn Any> reference to the object: Read moreSource§fn into_any(self: Box<T>) -> Box<dyn Any + Sync + Send>
fn into_any(self: Box<T>) -> Box<dyn Any + Sync + Send>
Box<dyn Any>: Read moreSource§fn type_name(&self) -> &'static str
fn type_name(&self) -> &'static str
std::any::type_name, since Any does not provide it and
Any::type_id is useless as a debugging aid (its Debug is just a mess of hex digits).Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for T
impl<T> Downcast for T
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::RequestSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Requestimpl<T> MaybeSend for Twhere
T: Send,
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.