provisioning/docs/book/architecture/integration-patterns.html
Jesús Pérez 6a59d34bb1
chore: update provisioning configuration and documentation
Update configuration files, templates, and internal documentation
for the provisioning repository system.

Configuration Updates:
- KMS configuration modernization
- Plugin system settings
- Service port mappings
- Test cluster topologies
- Installation configuration examples
- VM configuration defaults
- Cedar authorization policies

Documentation Updates:
- Library module documentation
- Extension API guides
- AI system documentation
- Service management guides
- Test environment setup
- Plugin usage guides
- Validator configuration documentation

All changes are backward compatible.
2025-12-11 21:50:42 +00:00

752 lines
31 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="ayu sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Integration Patterns - Provisioning Platform Documentation</title>
<!-- Custom HTML head -->
<meta name="description" content="Complete documentation for the Provisioning Platform - Infrastructure automation with Nushell, KCL, and Rust">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "ayu";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('ayu')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Provisioning Platform Documentation</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/provisioning/provisioning-platform" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/provisioning/provisioning-platform/edit/main/provisioning/docs/src/architecture/integration-patterns.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="integration-patterns"><a class="header" href="#integration-patterns">Integration Patterns</a></h1>
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
<p>Provisioning implements sophisticated integration patterns to coordinate between its hybrid Rust/Nushell architecture, manage multi-provider workflows, and enable extensible functionality. This document outlines the key integration patterns, their implementations, and best practices.</p>
<h2 id="core-integration-patterns"><a class="header" href="#core-integration-patterns">Core Integration Patterns</a></h2>
<h3 id="1-hybrid-language-integration"><a class="header" href="#1-hybrid-language-integration">1. Hybrid Language Integration</a></h3>
<h4 id="rust-to-nushell-communication-pattern"><a class="header" href="#rust-to-nushell-communication-pattern">Rust-to-Nushell Communication Pattern</a></h4>
<p><strong>Use Case</strong>: Orchestrator invoking business logic operations</p>
<p><strong>Implementation</strong>:</p>
<pre><code class="language-rust">use tokio::process::Command;
use serde_json;
pub async fn execute_nushell_workflow(
workflow: &amp;str,
args: &amp;[String]
) -&gt; Result&lt;WorkflowResult, Error&gt; {
let mut cmd = Command::new("nu");
cmd.arg("-c")
.arg(format!("use core/nulib/workflows/{}.nu *; {}", workflow, args.join(" ")));
let output = cmd.output().await?;
let result: WorkflowResult = serde_json::from_slice(&amp;output.stdout)?;
Ok(result)
}</code></pre>
<p><strong>Data Exchange Format</strong>:</p>
<pre><code class="language-json">{
"status": "success" | "error" | "partial",
"result": {
"operation": "server_create",
"resources": ["server-001", "server-002"],
"metadata": { ... }
},
"error": null | { "code": "ERR001", "message": "..." },
"context": { "workflow_id": "wf-123", "step": 2 }
}
</code></pre>
<h4 id="nushell-to-rust-communication-pattern"><a class="header" href="#nushell-to-rust-communication-pattern">Nushell-to-Rust Communication Pattern</a></h4>
<p><strong>Use Case</strong>: Business logic submitting workflows to orchestrator</p>
<p><strong>Implementation</strong>:</p>
<pre><code class="language-nushell">def submit-workflow [workflow: record] -&gt; record {
let payload = $workflow | to json
http post "http://localhost:9090/workflows/submit" {
headers: { "Content-Type": "application/json" }
body: $payload
}
| from json
}
</code></pre>
<p><strong>API Contract</strong>:</p>
<pre><code class="language-json">{
"workflow_id": "wf-456",
"name": "multi_cloud_deployment",
"operations": [...],
"dependencies": { ... },
"configuration": { ... }
}
</code></pre>
<h3 id="2-provider-abstraction-pattern"><a class="header" href="#2-provider-abstraction-pattern">2. Provider Abstraction Pattern</a></h3>
<h4 id="standard-provider-interface"><a class="header" href="#standard-provider-interface">Standard Provider Interface</a></h4>
<p><strong>Purpose</strong>: Uniform API across different cloud providers</p>
<p><strong>Interface Definition</strong>:</p>
<pre><code class="language-nushell"># Standard provider interface that all providers must implement
export def list-servers [] -&gt; table {
# Provider-specific implementation
}
export def create-server [config: record] -&gt; record {
# Provider-specific implementation
}
export def delete-server [id: string] -&gt; nothing {
# Provider-specific implementation
}
export def get-server [id: string] -&gt; record {
# Provider-specific implementation
}
</code></pre>
<p><strong>Configuration Integration</strong>:</p>
<pre><code class="language-toml">[providers.aws]
region = "us-west-2"
credentials_profile = "default"
timeout = 300
[providers.upcloud]
zone = "de-fra1"
api_endpoint = "https://api.upcloud.com"
timeout = 180
[providers.local]
docker_socket = "/var/run/docker.sock"
network_mode = "bridge"
</code></pre>
<h4 id="provider-discovery-and-loading"><a class="header" href="#provider-discovery-and-loading">Provider Discovery and Loading</a></h4>
<pre><code class="language-nushell">def load-providers [] -&gt; table {
let provider_dirs = glob "providers/*/nulib"
$provider_dirs
| each { |dir|
let provider_name = $dir | path basename | path dirname | path basename
let provider_config = get-provider-config $provider_name
{
name: $provider_name,
path: $dir,
config: $provider_config,
available: (test-provider-connectivity $provider_name)
}
}
}
</code></pre>
<h3 id="3-configuration-resolution-pattern"><a class="header" href="#3-configuration-resolution-pattern">3. Configuration Resolution Pattern</a></h3>
<h4 id="hierarchical-configuration-loading"><a class="header" href="#hierarchical-configuration-loading">Hierarchical Configuration Loading</a></h4>
<p><strong>Implementation</strong>:</p>
<pre><code class="language-nushell">def resolve-configuration [context: record] -&gt; record {
let base_config = open config.defaults.toml
let user_config = if ("config.user.toml" | path exists) {
open config.user.toml
} else { {} }
let env_config = if ($env.PROVISIONING_ENV? | is-not-empty) {
let env_file = $"config.($env.PROVISIONING_ENV).toml"
if ($env_file | path exists) { open $env_file } else { {} }
} else { {} }
let merged_config = $base_config
| merge $user_config
| merge $env_config
| merge ($context.runtime_config? | default {})
interpolate-variables $merged_config
}
</code></pre>
<h4 id="variable-interpolation-pattern"><a class="header" href="#variable-interpolation-pattern">Variable Interpolation Pattern</a></h4>
<pre><code class="language-nushell">def interpolate-variables [config: record] -&gt; record {
let interpolations = {
"{{paths.base}}": ($env.PWD),
"{{env.HOME}}": ($env.HOME),
"{{now.date}}": (date now | format date "%Y-%m-%d"),
"{{git.branch}}": (git branch --show-current | str trim)
}
$config
| to json
| str replace --all "{{paths.base}}" $interpolations."{{paths.base}}"
| str replace --all "{{env.HOME}}" $interpolations."{{env.HOME}}"
| str replace --all "{{now.date}}" $interpolations."{{now.date}}"
| str replace --all "{{git.branch}}" $interpolations."{{git.branch}}"
| from json
}
</code></pre>
<h3 id="4-workflow-orchestration-patterns"><a class="header" href="#4-workflow-orchestration-patterns">4. Workflow Orchestration Patterns</a></h3>
<h4 id="dependency-resolution-pattern"><a class="header" href="#dependency-resolution-pattern">Dependency Resolution Pattern</a></h4>
<p><strong>Use Case</strong>: Managing complex workflow dependencies</p>
<p><strong>Implementation (Rust)</strong>:</p>
<pre><code class="language-rust">use petgraph::{Graph, Direction};
use std::collections::HashMap;
pub struct DependencyResolver {
graph: Graph&lt;String, ()&gt;,
node_map: HashMap&lt;String, petgraph::graph::NodeIndex&gt;,
}
impl DependencyResolver {
pub fn resolve_execution_order(&amp;self) -&gt; Result&lt;Vec&lt;String&gt;, Error&gt; {
let mut topo = petgraph::algo::toposort(&amp;self.graph, None)
.map_err(|_| Error::CyclicDependency)?;
Ok(topo.into_iter()
.map(|idx| self.graph[idx].clone())
.collect())
}
pub fn add_dependency(&amp;mut self, from: &amp;str, to: &amp;str) {
let from_idx = self.get_or_create_node(from);
let to_idx = self.get_or_create_node(to);
self.graph.add_edge(from_idx, to_idx, ());
}
}</code></pre>
<h4 id="parallel-execution-pattern"><a class="header" href="#parallel-execution-pattern">Parallel Execution Pattern</a></h4>
<pre><code class="language-rust">use tokio::task::JoinSet;
use futures::stream::{FuturesUnordered, StreamExt};
pub async fn execute_parallel_batch(
operations: Vec&lt;Operation&gt;,
parallelism_limit: usize
) -&gt; Result&lt;Vec&lt;OperationResult&gt;, Error&gt; {
let semaphore = tokio::sync::Semaphore::new(parallelism_limit);
let mut join_set = JoinSet::new();
for operation in operations {
let permit = semaphore.clone();
join_set.spawn(async move {
let _permit = permit.acquire().await?;
execute_operation(operation).await
});
}
let mut results = Vec::new();
while let Some(result) = join_set.join_next().await {
results.push(result??);
}
Ok(results)
}</code></pre>
<h3 id="5-state-management-patterns"><a class="header" href="#5-state-management-patterns">5. State Management Patterns</a></h3>
<h4 id="checkpoint-based-recovery-pattern"><a class="header" href="#checkpoint-based-recovery-pattern">Checkpoint-Based Recovery Pattern</a></h4>
<p><strong>Use Case</strong>: Reliable state persistence and recovery</p>
<p><strong>Implementation</strong>:</p>
<pre><code class="language-rust">#[derive(Serialize, Deserialize)]
pub struct WorkflowCheckpoint {
pub workflow_id: String,
pub step: usize,
pub completed_operations: Vec&lt;String&gt;,
pub current_state: serde_json::Value,
pub metadata: HashMap&lt;String, String&gt;,
pub timestamp: chrono::DateTime&lt;chrono::Utc&gt;,
}
pub struct CheckpointManager {
checkpoint_dir: PathBuf,
}
impl CheckpointManager {
pub fn save_checkpoint(&amp;self, checkpoint: &amp;WorkflowCheckpoint) -&gt; Result&lt;(), Error&gt; {
let checkpoint_file = self.checkpoint_dir
.join(&amp;checkpoint.workflow_id)
.with_extension("json");
let checkpoint_data = serde_json::to_string_pretty(checkpoint)?;
std::fs::write(checkpoint_file, checkpoint_data)?;
Ok(())
}
pub fn restore_checkpoint(&amp;self, workflow_id: &amp;str) -&gt; Result&lt;Option&lt;WorkflowCheckpoint&gt;, Error&gt; {
let checkpoint_file = self.checkpoint_dir
.join(workflow_id)
.with_extension("json");
if checkpoint_file.exists() {
let checkpoint_data = std::fs::read_to_string(checkpoint_file)?;
let checkpoint = serde_json::from_str(&amp;checkpoint_data)?;
Ok(Some(checkpoint))
} else {
Ok(None)
}
}
}</code></pre>
<h4 id="rollback-pattern"><a class="header" href="#rollback-pattern">Rollback Pattern</a></h4>
<pre><code class="language-rust">pub struct RollbackManager {
rollback_stack: Vec&lt;RollbackAction&gt;,
}
#[derive(Clone, Debug)]
pub enum RollbackAction {
DeleteResource { provider: String, resource_id: String },
RestoreFile { path: PathBuf, content: String },
RevertConfiguration { key: String, value: serde_json::Value },
CustomAction { command: String, args: Vec&lt;String&gt; },
}
impl RollbackManager {
pub async fn execute_rollback(&amp;self) -&gt; Result&lt;(), Error&gt; {
// Execute rollback actions in reverse order
for action in self.rollback_stack.iter().rev() {
match action {
RollbackAction::DeleteResource { provider, resource_id } =&gt; {
self.delete_resource(provider, resource_id).await?;
}
RollbackAction::RestoreFile { path, content } =&gt; {
tokio::fs::write(path, content).await?;
}
// ... handle other rollback actions
}
}
Ok(())
}
}</code></pre>
<h3 id="6-event-and-messaging-patterns"><a class="header" href="#6-event-and-messaging-patterns">6. Event and Messaging Patterns</a></h3>
<h4 id="event-driven-architecture-pattern"><a class="header" href="#event-driven-architecture-pattern">Event-Driven Architecture Pattern</a></h4>
<p><strong>Use Case</strong>: Decoupled communication between components</p>
<p><strong>Event Definition</strong>:</p>
<pre><code class="language-rust">#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SystemEvent {
WorkflowStarted { workflow_id: String, name: String },
WorkflowCompleted { workflow_id: String, result: WorkflowResult },
WorkflowFailed { workflow_id: String, error: String },
ResourceCreated { provider: String, resource_type: String, resource_id: String },
ResourceDeleted { provider: String, resource_type: String, resource_id: String },
ConfigurationChanged { key: String, old_value: serde_json::Value, new_value: serde_json::Value },
}</code></pre>
<p><strong>Event Bus Implementation</strong>:</p>
<pre><code class="language-rust">use tokio::sync::broadcast;
pub struct EventBus {
sender: broadcast::Sender&lt;SystemEvent&gt;,
}
impl EventBus {
pub fn new(capacity: usize) -&gt; Self {
let (sender, _) = broadcast::channel(capacity);
Self { sender }
}
pub fn publish(&amp;self, event: SystemEvent) -&gt; Result&lt;(), Error&gt; {
self.sender.send(event)
.map_err(|_| Error::EventPublishFailed)?;
Ok(())
}
pub fn subscribe(&amp;self) -&gt; broadcast::Receiver&lt;SystemEvent&gt; {
self.sender.subscribe()
}
}</code></pre>
<h3 id="7-extension-integration-patterns"><a class="header" href="#7-extension-integration-patterns">7. Extension Integration Patterns</a></h3>
<h4 id="extension-discovery-and-loading"><a class="header" href="#extension-discovery-and-loading">Extension Discovery and Loading</a></h4>
<pre><code class="language-nushell">def discover-extensions [] -&gt; table {
let extension_dirs = glob "extensions/*/extension.toml"
$extension_dirs
| each { |manifest_path|
let extension_dir = $manifest_path | path dirname
let manifest = open $manifest_path
{
name: $manifest.extension.name,
version: $manifest.extension.version,
type: $manifest.extension.type,
path: $extension_dir,
manifest: $manifest,
valid: (validate-extension $manifest),
compatible: (check-compatibility $manifest.compatibility)
}
}
| where valid and compatible
}
</code></pre>
<h4 id="extension-interface-pattern"><a class="header" href="#extension-interface-pattern">Extension Interface Pattern</a></h4>
<pre><code class="language-nushell"># Standard extension interface
export def extension-info [] -&gt; record {
{
name: "custom-provider",
version: "1.0.0",
type: "provider",
description: "Custom cloud provider integration",
entry_points: {
cli: "nulib/cli.nu",
provider: "nulib/provider.nu"
}
}
}
export def extension-validate [] -&gt; bool {
# Validate extension configuration and dependencies
true
}
export def extension-activate [] -&gt; nothing {
# Perform extension activation tasks
}
export def extension-deactivate [] -&gt; nothing {
# Perform extension cleanup tasks
}
</code></pre>
<h3 id="8-api-design-patterns"><a class="header" href="#8-api-design-patterns">8. API Design Patterns</a></h3>
<h4 id="rest-api-standardization"><a class="header" href="#rest-api-standardization">REST API Standardization</a></h4>
<p><strong>Base API Structure</strong>:</p>
<pre><code class="language-rust">use axum::{
extract::{Path, State},
response::Json,
routing::{get, post, delete},
Router,
};
pub fn create_api_router(state: AppState) -&gt; Router {
Router::new()
.route("/health", get(health_check))
.route("/workflows", get(list_workflows).post(create_workflow))
.route("/workflows/:id", get(get_workflow).delete(delete_workflow))
.route("/workflows/:id/status", get(workflow_status))
.route("/workflows/:id/logs", get(workflow_logs))
.with_state(state)
}</code></pre>
<p><strong>Standard Response Format</strong>:</p>
<pre><code class="language-json">{
"status": "success" | "error" | "pending",
"data": { ... },
"metadata": {
"timestamp": "2025-09-26T12:00:00Z",
"request_id": "req-123",
"version": "3.1.0"
},
"error": null | {
"code": "ERR001",
"message": "Human readable error",
"details": { ... }
}
}
</code></pre>
<h2 id="error-handling-patterns"><a class="header" href="#error-handling-patterns">Error Handling Patterns</a></h2>
<h3 id="structured-error-pattern"><a class="header" href="#structured-error-pattern">Structured Error Pattern</a></h3>
<pre><code class="language-rust">#[derive(thiserror::Error, Debug)]
pub enum ProvisioningError {
#[error("Configuration error: {message}")]
Configuration { message: String },
#[error("Provider error [{provider}]: {message}")]
Provider { provider: String, message: String },
#[error("Workflow error [{workflow_id}]: {message}")]
Workflow { workflow_id: String, message: String },
#[error("Resource error [{resource_type}/{resource_id}]: {message}")]
Resource { resource_type: String, resource_id: String, message: String },
}</code></pre>
<h3 id="error-recovery-pattern"><a class="header" href="#error-recovery-pattern">Error Recovery Pattern</a></h3>
<pre><code class="language-nushell">def with-retry [operation: closure, max_attempts: int = 3] {
mut attempts = 0
mut last_error = null
while $attempts &lt; $max_attempts {
try {
return (do $operation)
} catch { |error|
$attempts = $attempts + 1
$last_error = $error
if $attempts &lt; $max_attempts {
let delay = (2 ** ($attempts - 1)) * 1000 # Exponential backoff
sleep $"($delay)ms"
}
}
}
error make { msg: $"Operation failed after ($max_attempts) attempts: ($last_error)" }
}
</code></pre>
<h2 id="performance-optimization-patterns"><a class="header" href="#performance-optimization-patterns">Performance Optimization Patterns</a></h2>
<h3 id="caching-strategy-pattern"><a class="header" href="#caching-strategy-pattern">Caching Strategy Pattern</a></h3>
<pre><code class="language-rust">use std::sync::Arc;
use tokio::sync::RwLock;
use std::collections::HashMap;
use chrono::{DateTime, Utc, Duration};
#[derive(Clone)]
pub struct CacheEntry&lt;T&gt; {
pub value: T,
pub expires_at: DateTime&lt;Utc&gt;,
}
pub struct Cache&lt;T&gt; {
store: Arc&lt;RwLock&lt;HashMap&lt;String, CacheEntry&lt;T&gt;&gt;&gt;&gt;,
default_ttl: Duration,
}
impl&lt;T: Clone&gt; Cache&lt;T&gt; {
pub async fn get(&amp;self, key: &amp;str) -&gt; Option&lt;T&gt; {
let store = self.store.read().await;
if let Some(entry) = store.get(key) {
if entry.expires_at &gt; Utc::now() {
Some(entry.value.clone())
} else {
None
}
} else {
None
}
}
pub async fn set(&amp;self, key: String, value: T) {
let expires_at = Utc::now() + self.default_ttl;
let entry = CacheEntry { value, expires_at };
let mut store = self.store.write().await;
store.insert(key, entry);
}
}</code></pre>
<h3 id="streaming-pattern-for-large-data"><a class="header" href="#streaming-pattern-for-large-data">Streaming Pattern for Large Data</a></h3>
<pre><code class="language-nushell">def process-large-dataset [source: string] -&gt; nothing {
# Stream processing instead of loading entire dataset
open $source
| lines
| each { |line|
# Process line individually
$line | process-record
}
| save output.json
}
</code></pre>
<h2 id="testing-integration-patterns"><a class="header" href="#testing-integration-patterns">Testing Integration Patterns</a></h2>
<h3 id="integration-test-pattern"><a class="header" href="#integration-test-pattern">Integration Test Pattern</a></h3>
<pre><code class="language-rust">#[cfg(test)]
mod integration_tests {
use super::*;
use tokio_test;
#[tokio::test]
async fn test_workflow_execution() {
let orchestrator = setup_test_orchestrator().await;
let workflow = create_test_workflow();
let result = orchestrator.execute_workflow(workflow).await;
assert!(result.is_ok());
assert_eq!(result.unwrap().status, WorkflowStatus::Completed);
}
}</code></pre>
<p>These integration patterns provide the foundation for the systems sophisticated multi-component architecture, enabling reliable, scalable, and maintainable infrastructure automation.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../architecture/ARCHITECTURE_OVERVIEW.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../architecture/multi-repo-strategy.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../architecture/ARCHITECTURE_OVERVIEW.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../architecture/multi-repo-strategy.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>