-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
207 additions
and
3 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
use restate_sdk::prelude::*; | ||
use std::convert::Infallible; | ||
use std::time::Duration; | ||
use tracing::info; | ||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; | ||
|
||
#[restate_sdk::service] | ||
trait Greeter { | ||
async fn greet(name: String) -> Result<String, Infallible>; | ||
} | ||
|
||
struct GreeterImpl; | ||
|
||
impl Greeter for GreeterImpl { | ||
async fn greet(&self, ctx: Context<'_>, name: String) -> Result<String, Infallible> { | ||
let timeout = 60; // More than suspension timeout to trigger replay | ||
info!("This will be logged on replay"); | ||
_ = ctx.service_client::<DelayerClient>().delay(1).call().await; | ||
info!("This will not be logged on replay"); | ||
_ = ctx | ||
.service_client::<DelayerClient>() | ||
.delay(timeout) | ||
.call() | ||
.await; | ||
info!("This will be logged on processing after suspension"); | ||
Ok(format!("Greetings {name} after {timeout} seconds")) | ||
} | ||
} | ||
|
||
#[restate_sdk::service] | ||
trait Delayer { | ||
async fn delay(seconds: u64) -> Result<String, Infallible>; | ||
} | ||
|
||
struct DelayerImpl; | ||
|
||
impl Delayer for DelayerImpl { | ||
async fn delay(&self, ctx: Context<'_>, seconds: u64) -> Result<String, Infallible> { | ||
_ = ctx.sleep(Duration::from_secs(seconds)).await; | ||
info!("Delayed for {seconds} seconds"); | ||
Ok(format!("Delayed {seconds}")) | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let env_filter = tracing_subscriber::EnvFilter::try_from_default_env() | ||
.unwrap_or_else(|_| "restate_sdk=info".into()); | ||
let replay_filter = restate_sdk::filter::ReplayAwareFilter; | ||
tracing_subscriber::registry() | ||
.with( | ||
tracing_subscriber::fmt::layer() | ||
.with_filter(env_filter) | ||
.with_filter(replay_filter), | ||
) | ||
.init(); | ||
HttpServer::new( | ||
Endpoint::builder() | ||
.bind(GreeterImpl.serve()) | ||
.bind(DelayerImpl.serve()) | ||
.build(), | ||
) | ||
.listen_and_serve("0.0.0.0:9080".parse().unwrap()) | ||
.await; | ||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
//! Replay aware tracing filter | ||
//! | ||
//! Use this filter to skip tracing events in the service/workflow while replaying. | ||
//! | ||
//! Example: | ||
//! ```rust,no_run | ||
//! use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; | ||
//! let replay_filter = restate_sdk::filter::ReplayAwareFilter; | ||
//! tracing_subscriber::registry() | ||
//! .with(tracing_subscriber::fmt::layer().with_filter(replay_filter)) | ||
//! .init(); | ||
//! ``` | ||
use std::fmt::Debug; | ||
use tracing::{ | ||
field::{Field, Visit}, | ||
span::{Attributes, Record}, | ||
Event, Id, Metadata, Subscriber, | ||
}; | ||
use tracing_subscriber::{ | ||
layer::{Context, Filter}, | ||
registry::LookupSpan, | ||
Layer, | ||
}; | ||
|
||
#[derive(Debug)] | ||
struct ReplayField(bool); | ||
|
||
struct ReplayFieldVisitor(bool); | ||
|
||
impl Visit for ReplayFieldVisitor { | ||
fn record_bool(&mut self, field: &Field, value: bool) { | ||
if field.name().eq("replaying") { | ||
self.0 = value; | ||
} | ||
} | ||
|
||
fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {} | ||
} | ||
|
||
pub struct ReplayAwareFilter; | ||
|
||
impl<S: Subscriber + for<'lookup> LookupSpan<'lookup>> Filter<S> for ReplayAwareFilter { | ||
fn enabled(&self, _meta: &Metadata<'_>, _cx: &Context<'_, S>) -> bool { | ||
true | ||
} | ||
|
||
fn event_enabled(&self, event: &Event<'_>, cx: &Context<'_, S>) -> bool { | ||
if let Some(scope) = cx.event_scope(event) { | ||
if let Some(span) = scope.from_root().next() { | ||
let extensions = span.extensions(); | ||
if let Some(replay) = extensions.get::<ReplayField>() { | ||
return !replay.0; | ||
} | ||
} | ||
true | ||
} else { | ||
true | ||
} | ||
} | ||
|
||
fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) { | ||
if let Some(span) = ctx.span(id) { | ||
let mut visitor = ReplayFieldVisitor(false); | ||
attrs.record(&mut visitor); | ||
let mut extensions = span.extensions_mut(); | ||
extensions.insert::<ReplayField>(ReplayField(visitor.0)); | ||
} | ||
} | ||
|
||
fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) { | ||
if let Some(span) = ctx.span(id) { | ||
let mut visitor = ReplayFieldVisitor(false); | ||
values.record(&mut visitor); | ||
let mut extensions = span.extensions_mut(); | ||
extensions.replace::<ReplayField>(ReplayField(visitor.0)); | ||
} | ||
} | ||
} | ||
|
||
impl<S: Subscriber> Layer<S> for ReplayAwareFilter {} |
This file contains 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