-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make remote config usable in process, without manual FileStorage inte…
…raction Signed-off-by: Bob Weinand <[email protected]>
- Loading branch information
Showing
6 changed files
with
388 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use datadog_remote_config::fetch::{ConfigInvariants, SingleChangesFetcher}; | ||
use datadog_remote_config::file_change_tracker::{Change, FilePath}; | ||
use datadog_remote_config::file_storage::ParsedFileStorage; | ||
use datadog_remote_config::RemoteConfigProduct::ApmTracing; | ||
use datadog_remote_config::{RemoteConfigData, Target}; | ||
use ddcommon::Endpoint; | ||
use std::time::Duration; | ||
use tokio::time::sleep; | ||
|
||
const RUNTIME_ID: &str = "23e76587-5ae1-410c-a05c-137cae600a10"; | ||
const SERVICE: &str = "testservice"; | ||
const ENV: &str = "testenv"; | ||
const VERSION: &str = "1.2.3"; | ||
|
||
#[tokio::main(flavor = "current_thread")] | ||
async fn main() { | ||
// SingleChangesFetcher is ideal for a single static (runtime_id, service, env, version) tuple | ||
// Otherwise a SharedFetcher (or even a MultiTargetFetcher for a potentially high number of | ||
// targets) for multiple targets is needed. These can be manually wired together with a | ||
// ChangeTracker to keep track of changes. The SingleChangesTracker does it for you. | ||
let mut fetcher = SingleChangesFetcher::new( | ||
// Use SimpleFileStorage if you desire just the raw, unparsed contents | ||
// (e.g. to do processing directly in your language) | ||
// For more complicated use cases, like needing to store data in shared memory, a custom | ||
// FileStorage implementation is recommended | ||
ParsedFileStorage::default(), | ||
Target { | ||
service: SERVICE.to_string(), | ||
env: ENV.to_string(), | ||
app_version: VERSION.to_string(), | ||
}, | ||
RUNTIME_ID.to_string(), | ||
ConfigInvariants { | ||
language: "awesomelang".to_string(), | ||
tracer_version: "99.10.5".to_string(), | ||
endpoint: Endpoint { | ||
url: hyper::Uri::from_static("http://localhost:8126"), | ||
api_key: None, | ||
}, | ||
products: vec![ApmTracing], | ||
capabilities: vec![], | ||
}, | ||
); | ||
|
||
// Custom timeout, defaults to 5 seconds. | ||
fetcher.set_timeout(2000); | ||
|
||
loop { | ||
match fetcher.fetch_changes().await { | ||
Ok(changes) => { | ||
println!("Got {} changes:", changes.len()); | ||
for change in changes { | ||
match change { | ||
Change::Add(file) => { | ||
println!("Added file: {} (version: {})", file.path(), file.version()); | ||
print_file_contents(&file.contents()); | ||
} | ||
Change::Update(file, _) => { | ||
println!( | ||
"Got update for file: {} (version: {})", | ||
file.path(), | ||
file.version() | ||
); | ||
print_file_contents(&file.contents()); | ||
} | ||
Change::Remove(file) => { | ||
println!("Removing file {}", file.path()); | ||
} | ||
} | ||
} | ||
} | ||
Err(e) => { | ||
eprintln!("Fetch failed with {e}"); | ||
fetcher.set_last_error(e.to_string()); | ||
} | ||
} | ||
|
||
sleep(Duration::from_nanos(fetcher.get_interval()).max(Duration::from_secs(1))).await; | ||
} | ||
} | ||
|
||
fn print_file_contents(contents: &anyhow::Result<RemoteConfigData>) { | ||
match contents { | ||
Ok(data) => { | ||
println!("File contents: {:?}", data); | ||
} | ||
Err(e) => { | ||
println!("Failed parsing file: {:?}", e); | ||
} | ||
} | ||
} |
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,78 @@ | ||
// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use crate::RemoteConfigPath; | ||
use std::collections::HashSet; | ||
use std::hash::{Hash, Hasher}; | ||
use std::sync::Arc; | ||
|
||
pub trait FilePath { | ||
fn path(&self) -> &RemoteConfigPath; | ||
} | ||
|
||
pub trait UpdatedFiles<S: FilePath, R> { | ||
fn updated(&self) -> Vec<(Arc<S>, R)>; | ||
} | ||
|
||
struct FilePathBasedArc<S: FilePath>(Arc<S>); | ||
|
||
impl<S: FilePath> Hash for FilePathBasedArc<S> { | ||
fn hash<H: Hasher>(&self, state: &mut H) { | ||
self.0.path().hash(state) | ||
} | ||
} | ||
|
||
impl<S: FilePath> PartialEq for FilePathBasedArc<S> { | ||
fn eq(&self, other: &Self) -> bool { | ||
self.0.path() == other.0.path() | ||
} | ||
} | ||
|
||
impl<S: FilePath> Eq for FilePathBasedArc<S> {} | ||
|
||
pub struct ChangeTracker<S: FilePath> { | ||
last_files: HashSet<FilePathBasedArc<S>>, | ||
} | ||
|
||
impl<S: FilePath> Default for ChangeTracker<S> { | ||
fn default() -> Self { | ||
ChangeTracker { | ||
last_files: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
pub enum Change<S, R> { | ||
Add(S), | ||
Update(S, R), | ||
Remove(S), | ||
} | ||
|
||
impl<S: FilePath> ChangeTracker<S> { | ||
pub fn get_changes<R>( | ||
&mut self, | ||
files: Vec<Arc<S>>, | ||
updated: Vec<(Arc<S>, R)>, | ||
) -> Vec<Change<Arc<S>, R>> { | ||
let files = HashSet::from_iter(files.into_iter().map(FilePathBasedArc)); | ||
let mut changes = vec![]; | ||
|
||
for file in files.difference(&self.last_files) { | ||
changes.push(Change::Add(file.0.clone())); | ||
} | ||
|
||
for file in self.last_files.difference(&files) { | ||
changes.push(Change::Remove(file.0.clone())); | ||
} | ||
|
||
for (updated_file, old_contents) in updated.into_iter() { | ||
let file = FilePathBasedArc(updated_file); | ||
if files.contains(&file) { | ||
changes.push(Change::Update(file.0, old_contents)) | ||
} | ||
} | ||
|
||
self.last_files = files; | ||
changes | ||
} | ||
} |
Oops, something went wrong.