launchdarkly_server_sdk/migrations/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use core::fmt;
use std::fmt::{Display, Formatter};

use launchdarkly_server_sdk_evaluation::FlagValue;
use serde::{Deserialize, Serialize};

#[non_exhaustive]
#[derive(Debug, Copy, Clone, Serialize, Eq, Hash, PartialEq)]
#[serde(rename_all = "lowercase")]
/// Origin represents the source of origin for a migration-related operation.
pub enum Origin {
    /// Old represents the technology source we are migrating away from.
    Old,
    /// New represents the technology source we are migrating towards.
    New,
}

#[non_exhaustive]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
/// Operation represents a type of migration operation; namely, read or write.
pub enum Operation {
    /// Read denotes a read-related migration operation.
    Read,
    /// Write denotes a write-related migration operation.
    Write,
}

#[non_exhaustive]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
/// Stage denotes one of six possible stages a technology migration could be a
/// part of, progressing through the following order.
///
/// Off -> DualWrite -> Shadow -> Live -> RampDown -> Complete
pub enum Stage {
    /// Off - migration hasn't started, "old" is authoritative for reads and writes
    Off,
    /// DualWrite - write to both "old" and "new", "old" is authoritative for reads
    DualWrite,
    /// Shadow - both "new" and "old" versions run with a preference for "old"
    Shadow,
    /// Live - both "new" and "old" versions run with a preference for "new"
    Live,
    /// RampDown - only read from "new", write to "old" and "new"
    Rampdown,
    /// Complete - migration is done
    Complete,
}

impl Display for Stage {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Stage::Off => write!(f, "off"),
            Stage::DualWrite => write!(f, "dualwrite"),
            Stage::Shadow => write!(f, "shadow"),
            Stage::Live => write!(f, "live"),
            Stage::Rampdown => write!(f, "rampdown"),
            Stage::Complete => write!(f, "complete"),
        }
    }
}

impl From<Stage> for FlagValue {
    fn from(stage: Stage) -> FlagValue {
        FlagValue::Str(stage.to_string())
    }
}

impl TryFrom<FlagValue> for Stage {
    type Error = String;

    fn try_from(value: FlagValue) -> Result<Self, Self::Error> {
        if let FlagValue::Str(value) = value {
            match value.as_str() {
                "off" => Ok(Stage::Off),
                "dualwrite" => Ok(Stage::DualWrite),
                "shadow" => Ok(Stage::Shadow),
                "live" => Ok(Stage::Live),
                "rampdown" => Ok(Stage::Rampdown),
                "complete" => Ok(Stage::Complete),
                _ => Err(format!("Invalid stage: {}", value)),
            }
        } else {
            Err("Cannot convert non-string value to Stage".to_string())
        }
    }
}

#[non_exhaustive]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
/// ExecutionOrder represents the various execution modes this SDK can operate under while
/// performing migration-assisted reads.
pub enum ExecutionOrder {
    /// Serial execution ensures the authoritative read will always complete execution before
    /// executing the non-authoritative read.
    Serial,
    /// Random execution randomly decides if the authoritative read should execute first or second.
    Random,
    /// Concurrent executes both concurrently, waiting until both calls have finished before
    /// proceeding.
    Concurrent,
}

pub use migrator::Migrator;
pub use migrator::MigratorBuilder;
pub use tracker::MigrationOpTracker;

mod migrator;
mod tracker;