Skip to main content

Redis

Struct Redis 

Source
pub struct Redis { /* private fields */ }
Expand description

A key in Redis, as a configuration source.

Not Clone: it holds a connection, and two clones sharing a key while each opening their own would double the connections for no gain. Wrap it in an Arc if two places need one.

Implementations§

Source§

impl Redis

Source

pub fn new(url: &str, keys: impl Into<Keys>) -> Result<Self, Error>

The key key, on the Redis at url.

The format is taken from the key’s extension — myapp/db.json is JSON. A key without one needs with_format.

§Errors

If the URL cannot be parsed. Not if the server is unreachable: the connection is opened on the first read, so that construction stays free of I/O like every other source in this family.

Source

pub fn with_tls( url: &str, keys: impl Into<Keys>, tls: &TlsConfig, ) -> Result<Self, Error>

Available on crate feature tls only.

The key key on the Redis at url, with a private certificate authority or a client certificate.

The same three settings, spelled the same way, in all seven store crates — and spelled as data, so nothing here names a redis type:

let redis = Redis::with_tls(
    "rediss://cache.internal:6379",
    "myapp/db.json",
    &TlsConfig::new().with_ca_certificate_file("/etc/ssl/private-ca.pem"),
)?;

Redis expresses all of it: a CA from a file or from bytes, and a client certificate from either. The credentials still travel in the URL, as they do for new.

The URL must be rediss://. A redis:// URL with TLS material is a deployment that believes it is encrypted and is not, so it is refused here rather than by the client three layers down.

There is no way to turn verification off; TlsConfig’s own documentation argues that one. Redis’ client has its own spelling — the #insecure URL fragment, behind a further feature — and it stays where it is, under its own frightening name.

§Errors

If the URL cannot be parsed, if it is not rediss://, if a PEM file cannot be read, or if the material is not PEM. Not if the server is unreachable: the connection is opened on the first read.

Source

pub fn from_client(client: Client, keys: impl Into<Keys>) -> Self

Uses a client the program already has.

For a caller that already talks to Redis, or one that built its client with options a URL cannot express — including a TLS configuration with_tls has no spelling for.

Source

pub fn with_format(self, format: Format) -> Self

States the format, for a key whose name does not.

Required for Keys::Prefix — a prefix has no extension — and it also settles a list whose keys name two different formats.

Source

pub fn with_timeout(self, timeout: Duration) -> Self

How long a single fetch may take before it is given up on. Ten seconds by default.

The deadline for one fetch attempt, excluding retries the underlying client performs — the same sentence every store in this family answers to. Redis splits it into three, and this sets all of them from the one value: opening the connection, writing the command, and waiting for the reply.

All three, because any one of them alone is the mistake: a deadline that only covers connecting sails straight past a server that accepted the socket and then stopped answering, which is what a wedged Redis actually looks like.

It bounds each read watch performs, not the watch itself — a subscription waiting for the next notification is supposed to wait.

Source

pub fn reporting_to(self, sink: RemoteSink) -> Self

Reports this source’s watch failures to sink.

A watch loop is the half of a store dynamic-config cannot see. A delivery keeps RemoteStatus current because RemoteSink::apply records one — but a loop whose subscription died, or whose re-read keeps failing, delivers nothing and would otherwise say nothing: dynamic_config_remote_up would report the last delivery rather than the last attempt, and a Redis that stopped answering an hour ago would look healthy until something called refresh_remote().

// Taken once, where the loop is wired: a sink captures the generation
// of the source installed at that moment, which is what stops a loop
// winding down from charging its failures to its replacement.
let sink = DbConfig::remote_sink();

let watcher = Redis::new(url, "myapp/db.json")?.reporting_to(sink);

A failure moves the failure streak and nothing else. The fetch count and the clock are left alone, so dynamic_config_remote_last_fetch_seconds keeps ageing while dynamic_config_remote_up goes to zero — the pair an alert wants. Only the failure’s kind and key path are recorded; a Redis URL never reaches a RemoteStatus.

It changes nothing about what watch returns, and nothing about fetch, which already records itself through refresh_remote().

Source

pub fn watch<F>(&self, watching: &Watching, on_change: F) -> Result<(), Error>
where F: FnMut(Fetched) -> Result<(), Error>,

Calls on_change whenever what this source reads changes.

Uses keyspace notifications: Redis publishes to __keyspace@{db}__:{key} when a key is written, and this subscribes to exactly that channel — one per key of the set. Genuinely change-driven — no polling, no timer.

One key or a named list. A named list is the multi-key case Redis can answer honestly, and the whole reason is MGET: it is one command, and Redis executes commands one at a time, so the values it answers with are the set as of one point in the command stream. The document delivered here is therefore a state the server really held — never one key’s new value beside another’s old one, which is the tear that made every other network store refuse. A prefix is refused; the reason is on Keys::Prefix.

What the read is not is simultaneous with the notification. It follows the event, so the document may be newer than the write that woke the loop, and two writes landing together can deliver the later state rather than each state in turn. Spurious, never torn — the same bargain dynamic-config-git’s watch makes, and the one that matters: a delivery is always a state the store was in, and never an older one than the delivery before it.

A named list therefore also coalesces: writing three keys together publishes three notifications and this delivers once, because the document the second and third would carry is the one already delivered. Every reload hook running three times for one deployment is a cost with nothing to buy it.

Keyspace notifications are off by default in Redis. A server that has not enabled them publishes nothing, and this loop would wait forever, so it checks at start-up and reports rather than hanging:

CONFIG SET notify-keyspace-events KEA

The current value is not delivered at startup, for the same reason a file watcher does not report an edit when it starts. Fetch first if the starting value matters.

A key that holds nothing is not a change this reports. For one key that is a deletion; for a named list it is one member of the set going away, which fails the read the same way fetch does — and a failed read here is treated as transient, because the next write notifies again. No configuration is not a configuration, so the running snapshot stays either way.

§What a failing loop reports

Nothing, unless reporting_to was given a sink. With one, the two failures inside the loop are reported to the RemoteStatus as they happen: a re-read that came back with nothing, and a subscription that died. The refusals at the door — a prefix, no format, no keys, notifications off, a server that will not accept the subscription — are not, because they are returned to the caller by this very call, before there is a loop to be silent in; and half of them are deployment mistakes rather than a store that stopped answering, which is not what dynamic_config_remote_up means.

§Errors

If the subscription cannot be established, if keyspace notifications are off, if the source reads a prefix, if the subscription itself breaks — a dead connection ends the watch with an error rather than spinning; restart it to resubscribe — or if on_change returns an error, so a caller that wants to survive a bad document should log it and return Ok.

Trait Implementations§

Source§

impl Debug for Redis

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl RemoteSource for Redis

Source§

fn fetch(&self) -> Result<Fetched, Error>

Reads the current document. Read more
Source§

fn describe(&self) -> String

How to name this source in an error or a report.

Auto Trait Implementations§

§

impl !Freeze for Redis

§

impl RefUnwindSafe for Redis

§

impl Send for Redis

§

impl Sync for Redis

§

impl Unpin for Redis

§

impl UnsafeUnpin for Redis

§

impl UnwindSafe for Redis

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> MaybeSendSync for T

Source§

impl<T> Paint for T
where T: ?Sized,

Source§

fn fg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the foreground set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like red() and green(), which have the same functionality but are pithier.

§Example

Set foreground color to white using fg():

use yansi::{Paint, Color};

painted.fg(Color::White);

Set foreground color to white using white().

use yansi::Paint;

painted.white();
Source§

fn primary(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Primary].

§Example
println!("{}", value.primary());
Source§

fn fixed(&self, color: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Fixed].

§Example
println!("{}", value.fixed(color));
Source§

fn rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Rgb].

§Example
println!("{}", value.rgb(r, g, b));
Source§

fn black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Black].

§Example
println!("{}", value.black());
Source§

fn red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Red].

§Example
println!("{}", value.red());
Source§

fn green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Green].

§Example
println!("{}", value.green());
Source§

fn yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Yellow].

§Example
println!("{}", value.yellow());
Source§

fn blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Blue].

§Example
println!("{}", value.blue());
Source§

fn magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Magenta].

§Example
println!("{}", value.magenta());
Source§

fn cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Cyan].

§Example
println!("{}", value.cyan());
Source§

fn white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: White].

§Example
println!("{}", value.white());
Source§

fn bright_black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlack].

§Example
println!("{}", value.bright_black());
Source§

fn bright_red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightRed].

§Example
println!("{}", value.bright_red());
Source§

fn bright_green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightGreen].

§Example
println!("{}", value.bright_green());
Source§

fn bright_yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightYellow].

§Example
println!("{}", value.bright_yellow());
Source§

fn bright_blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlue].

§Example
println!("{}", value.bright_blue());
Source§

fn bright_magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.bright_magenta());
Source§

fn bright_cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightCyan].

§Example
println!("{}", value.bright_cyan());
Source§

fn bright_white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightWhite].

§Example
println!("{}", value.bright_white());
Source§

fn bg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the background set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like on_red() and on_green(), which have the same functionality but are pithier.

§Example

Set background color to red using fg():

use yansi::{Paint, Color};

painted.bg(Color::Red);

Set background color to red using on_red().

use yansi::Paint;

painted.on_red();
Source§

fn on_primary(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Primary].

§Example
println!("{}", value.on_primary());
Source§

fn on_fixed(&self, color: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Fixed].

§Example
println!("{}", value.on_fixed(color));
Source§

fn on_rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Rgb].

§Example
println!("{}", value.on_rgb(r, g, b));
Source§

fn on_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Black].

§Example
println!("{}", value.on_black());
Source§

fn on_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Red].

§Example
println!("{}", value.on_red());
Source§

fn on_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Green].

§Example
println!("{}", value.on_green());
Source§

fn on_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Yellow].

§Example
println!("{}", value.on_yellow());
Source§

fn on_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Blue].

§Example
println!("{}", value.on_blue());
Source§

fn on_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Magenta].

§Example
println!("{}", value.on_magenta());
Source§

fn on_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Cyan].

§Example
println!("{}", value.on_cyan());
Source§

fn on_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: White].

§Example
println!("{}", value.on_white());
Source§

fn on_bright_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlack].

§Example
println!("{}", value.on_bright_black());
Source§

fn on_bright_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightRed].

§Example
println!("{}", value.on_bright_red());
Source§

fn on_bright_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightGreen].

§Example
println!("{}", value.on_bright_green());
Source§

fn on_bright_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightYellow].

§Example
println!("{}", value.on_bright_yellow());
Source§

fn on_bright_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlue].

§Example
println!("{}", value.on_bright_blue());
Source§

fn on_bright_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.on_bright_magenta());
Source§

fn on_bright_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightCyan].

§Example
println!("{}", value.on_bright_cyan());
Source§

fn on_bright_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightWhite].

§Example
println!("{}", value.on_bright_white());
Source§

fn attr(&self, value: Attribute) -> Painted<&T>

Enables the styling Attribute value.

This method should be used rarely. Instead, prefer to use attribute-specific builder methods like bold() and underline(), which have the same functionality but are pithier.

§Example

Make text bold using attr():

use yansi::{Paint, Attribute};

painted.attr(Attribute::Bold);

Make text bold using using bold().

use yansi::Paint;

painted.bold();
Source§

fn bold(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Bold].

§Example
println!("{}", value.bold());
Source§

fn dim(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Dim].

§Example
println!("{}", value.dim());
Source§

fn italic(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Italic].

§Example
println!("{}", value.italic());
Source§

fn underline(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Underline].

§Example
println!("{}", value.underline());

Returns self with the attr() set to [Attribute :: Blink].

§Example
println!("{}", value.blink());

Returns self with the attr() set to [Attribute :: RapidBlink].

§Example
println!("{}", value.rapid_blink());
Source§

fn invert(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Invert].

§Example
println!("{}", value.invert());
Source§

fn conceal(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Conceal].

§Example
println!("{}", value.conceal());
Source§

fn strike(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Strike].

§Example
println!("{}", value.strike());
Source§

fn quirk(&self, value: Quirk) -> Painted<&T>

Enables the yansi Quirk value.

This method should be used rarely. Instead, prefer to use quirk-specific builder methods like mask() and wrap(), which have the same functionality but are pithier.

§Example

Enable wrapping using .quirk():

use yansi::{Paint, Quirk};

painted.quirk(Quirk::Wrap);

Enable wrapping using wrap().

use yansi::Paint;

painted.wrap();
Source§

fn mask(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Mask].

§Example
println!("{}", value.mask());
Source§

fn wrap(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Wrap].

§Example
println!("{}", value.wrap());
Source§

fn linger(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Linger].

§Example
println!("{}", value.linger());
Source§

fn clear(&self) -> Painted<&T>

👎Deprecated since 1.0.1:

renamed to resetting() due to conflicts with Vec::clear(). The clear() method will be removed in a future release.

Returns self with the quirk() set to [Quirk :: Clear].

§Example
println!("{}", value.clear());
Source§

fn resetting(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Resetting].

§Example
println!("{}", value.resetting());
Source§

fn bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Bright].

§Example
println!("{}", value.bright());
Source§

fn on_bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: OnBright].

§Example
println!("{}", value.on_bright());
Source§

fn whenever(&self, value: Condition) -> Painted<&T>

Conditionally enable styling based on whether the Condition value applies. Replaces any previous condition.

See the crate level docs for more details.

§Example

Enable styling painted only when both stdout and stderr are TTYs:

use yansi::{Paint, Condition};

painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
Source§

fn new(self) -> Painted<Self>
where Self: Sized,

Create a new Painted with a default Style. Read more
Source§

fn paint<S>(&self, style: S) -> Painted<&Self>
where S: Into<Style>,

Apply a style wholesale to self. Any previous style is replaced. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.