|
1 | 1 | use std::time::Duration; |
2 | 2 |
|
3 | | -use anyhow::*; |
| 3 | +use anyhow::{Context, Result, anyhow}; |
4 | 4 | use clap::Parser; |
| 5 | +use indoc::formatdoc; |
5 | 6 | use rivet_service_manager::{CronConfig, RunConfig}; |
| 7 | +use universaldb::utils::IsolationLevel::*; |
| 8 | + |
| 9 | +use crate::keys; |
6 | 10 |
|
7 | 11 | // 7 day logs retention |
8 | 12 | const LOGS_RETENTION: Duration = Duration::from_secs(7 * 24 * 60 * 60); |
@@ -88,10 +92,52 @@ impl Opts { |
88 | 92 | .collect::<Vec<_>>() |
89 | 93 | }; |
90 | 94 |
|
91 | | - // Start server |
92 | 95 | let pools = rivet_pools::Pools::new(config.clone()).await?; |
| 96 | + |
| 97 | + verify_engine_version(&config, &pools).await?; |
| 98 | + |
| 99 | + // Start server |
93 | 100 | rivet_service_manager::start(config, pools, services).await?; |
94 | 101 |
|
95 | 102 | Ok(()) |
96 | 103 | } |
97 | 104 | } |
| 105 | + |
| 106 | +/// Verifies that no rollback has occurred (if allowing rollback is disabled). |
| 107 | +async fn verify_engine_version( |
| 108 | + config: &rivet_config::Config, |
| 109 | + pools: &rivet_pools::Pools, |
| 110 | +) -> Result<()> { |
| 111 | + if config.allow_version_rollback { |
| 112 | + return Ok(()); |
| 113 | + } |
| 114 | + |
| 115 | + pools |
| 116 | + .udb()? |
| 117 | + .run(|tx| async move { |
| 118 | + let current_version = semver::Version::parse(env!("CARGO_PKG_VERSION")) |
| 119 | + .context("failed to parse cargo pkg version as semver")?; |
| 120 | + |
| 121 | + if let Some(existing_version) = |
| 122 | + tx.read_opt(&keys::EngineVersionKey {}, Serializable).await? |
| 123 | + { |
| 124 | + if current_version < existing_version { |
| 125 | + return Ok(Err(anyhow!("{}", formatdoc!( |
| 126 | + " |
| 127 | + Rivet Engine has been rolled back to a previous version: |
| 128 | + - Last Used Version: {existing_version} |
| 129 | + - Current Version: {current_version} |
| 130 | + Cannot proceed without potential data corruption. |
| 131 | + |
| 132 | + (If you know what you're doing, this error can be disabled in the Rivet config via `allow_version_rollback: true`) |
| 133 | + " |
| 134 | + )))); |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + tx.write(&keys::EngineVersionKey {}, current_version)?; |
| 139 | + |
| 140 | + Ok(Ok(())) |
| 141 | + }) |
| 142 | + .await? |
| 143 | +} |
0 commit comments