linera_storage_service/
child.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use anyhow::{bail, Result};
5use linera_base::{command::CommandExt, time::Duration};
6use tokio::process::{Child, Command};
7
8use crate::client::{storage_service_check_absence, storage_service_check_validity};
9
10/// Configuration for a storage service running as a child process
11pub struct StorageService {
12    endpoint: String,
13    binary: String,
14}
15
16/// A storage service running as a child process.
17///
18/// The guard preserves the child from destruction and destroys it when
19/// it drops out of scope.
20pub struct StorageServiceGuard {
21    _child: Child,
22}
23
24impl StorageService {
25    /// Creates a new `StorageServiceChild`
26    pub fn new(endpoint: &str, binary: String) -> Self {
27        Self {
28            endpoint: endpoint.to_string(),
29            binary,
30        }
31    }
32
33    async fn command(&self) -> Command {
34        let mut command = Command::new(&self.binary);
35        command.args(["memory", "--endpoint", &self.endpoint]);
36        command.kill_on_drop(true);
37        command
38    }
39
40    /// Waits for the absence of the endpoint. If a child is terminated
41    /// then it might take time to wait for its absence.
42    async fn wait_for_absence(&self) -> Result<()> {
43        for i in 1..10 {
44            if storage_service_check_absence(&self.endpoint).await? {
45                return Ok(());
46            }
47            linera_base::time::timer::sleep(Duration::from_secs(i)).await;
48        }
49        bail!("Failed to start child server");
50    }
51
52    pub async fn run(&self) -> Result<StorageServiceGuard> {
53        self.wait_for_absence().await?;
54        let mut command = self.command().await;
55        let _child = command.spawn_into()?;
56        let guard = StorageServiceGuard { _child };
57        // We iterate until the child is spawned and can be accessed.
58        // We add an additional waiting period to avoid problems.
59        for i in 1..10 {
60            let result = storage_service_check_validity(&self.endpoint).await;
61            if result.is_ok() {
62                return Ok(guard);
63            }
64            linera_base::time::timer::sleep(Duration::from_secs(i)).await;
65        }
66        bail!("Failed to start child server");
67    }
68}