Fix SurrealDB reconnect on mission restart
This commit is contained in:
parent
2cdf4db591
commit
5a48cbfa4a
@ -6,6 +6,8 @@ PREP_RECOMPILE_END;
|
|||||||
|
|
||||||
GVAR(PlayerBootstrapRegistry) = createHashMap;
|
GVAR(PlayerBootstrapRegistry) = createHashMap;
|
||||||
|
|
||||||
|
if (isServer) then { "forge_server" callExtension ["surreal:reconnect", []]; };
|
||||||
|
|
||||||
["forge_icom_event", {
|
["forge_icom_event", {
|
||||||
params [["_event", "", [""]], ["_data", createHashMap, [createHashMap]]];
|
params [["_event", "", [""]], ["_data", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
//! SurrealDB connection bootstrap for persistent storage.
|
//! SurrealDB connection bootstrap for persistent storage.
|
||||||
|
|
||||||
use arma_rs::Group;
|
use arma_rs::Group;
|
||||||
use std::sync::{LazyLock, OnceLock, RwLock as StdRwLock};
|
use std::sync::{
|
||||||
|
Arc, LazyLock, RwLock as StdRwLock,
|
||||||
|
atomic::{AtomicU64, Ordering},
|
||||||
|
};
|
||||||
use surrealdb::Surreal;
|
use surrealdb::Surreal;
|
||||||
use surrealdb::engine::remote::http::{Client, Http};
|
use surrealdb::engine::remote::http::{Client, Http};
|
||||||
use surrealdb::opt::auth::Root;
|
use surrealdb::opt::auth::Root;
|
||||||
@ -10,17 +13,20 @@ use tokio::time::{Duration, sleep, timeout};
|
|||||||
use crate::config::SurrealConfig;
|
use crate::config::SurrealConfig;
|
||||||
use crate::log;
|
use crate::log;
|
||||||
use crate::schema;
|
use crate::schema;
|
||||||
|
use crate::{RUNTIME, config};
|
||||||
|
|
||||||
pub type SurrealDb = Surreal<Client>;
|
pub type SurrealDb = Surreal<Client>;
|
||||||
|
|
||||||
const CLIENT_READY_TIMEOUT: Duration = Duration::from_secs(30);
|
const CLIENT_READY_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
const CLIENT_READY_POLL_INTERVAL: Duration = Duration::from_millis(25);
|
const CLIENT_READY_POLL_INTERVAL: Duration = Duration::from_millis(25);
|
||||||
|
|
||||||
static SURREAL_DB: OnceLock<SurrealDb> = OnceLock::new();
|
static SURREAL_DB: LazyLock<StdRwLock<Option<Arc<SurrealDb>>>> =
|
||||||
|
LazyLock::new(|| StdRwLock::new(None));
|
||||||
static SURREAL_CONNECTION_STATE: LazyLock<StdRwLock<SurrealConnectionState>> =
|
static SURREAL_CONNECTION_STATE: LazyLock<StdRwLock<SurrealConnectionState>> =
|
||||||
LazyLock::new(|| StdRwLock::new(SurrealConnectionState::Disabled));
|
LazyLock::new(|| StdRwLock::new(SurrealConnectionState::Disabled));
|
||||||
static SURREAL_FAILURE_REASON: LazyLock<StdRwLock<Option<String>>> =
|
static SURREAL_FAILURE_REASON: LazyLock<StdRwLock<Option<String>>> =
|
||||||
LazyLock::new(|| StdRwLock::new(None));
|
LazyLock::new(|| StdRwLock::new(None));
|
||||||
|
static SURREAL_INIT_GENERATION: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum SurrealConnectionState {
|
enum SurrealConnectionState {
|
||||||
@ -36,6 +42,7 @@ pub fn prepare() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn initialize(config: SurrealConfig) {
|
pub async fn initialize(config: SurrealConfig) {
|
||||||
|
let generation = SURREAL_INIT_GENERATION.fetch_add(1, Ordering::SeqCst) + 1;
|
||||||
prepare();
|
prepare();
|
||||||
|
|
||||||
log::log(
|
log::log(
|
||||||
@ -52,6 +59,9 @@ pub async fn initialize(config: SurrealConfig) {
|
|||||||
|
|
||||||
let db = match connection {
|
let db = match connection {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
if !is_current_generation(generation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
log::log(
|
log::log(
|
||||||
"surreal",
|
"surreal",
|
||||||
"ERROR",
|
"ERROR",
|
||||||
@ -69,6 +79,9 @@ pub async fn initialize(config: SurrealConfig) {
|
|||||||
}
|
}
|
||||||
Ok(Ok(db)) => db,
|
Ok(Ok(db)) => db,
|
||||||
Ok(Err(error)) => {
|
Ok(Err(error)) => {
|
||||||
|
if !is_current_generation(generation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
log::log(
|
log::log(
|
||||||
"surreal",
|
"surreal",
|
||||||
"ERROR",
|
"ERROR",
|
||||||
@ -80,8 +93,15 @@ pub async fn initialize(config: SurrealConfig) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !is_current_generation(generation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log::log("surreal", "DEBUG", "Applying SurrealDB schemas");
|
log::log("surreal", "DEBUG", "Applying SurrealDB schemas");
|
||||||
if let Err(error) = schema::apply_all(&db).await {
|
if let Err(error) = schema::apply_all(&db).await {
|
||||||
|
if !is_current_generation(generation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
log::log(
|
log::log(
|
||||||
"surreal",
|
"surreal",
|
||||||
"ERROR",
|
"ERROR",
|
||||||
@ -92,20 +112,23 @@ pub async fn initialize(config: SurrealConfig) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if SURREAL_DB.set(db).is_ok() {
|
if !is_current_generation(generation) {
|
||||||
log::log("surreal", "INFO", "Connected to SurrealDB server");
|
return;
|
||||||
*SURREAL_CONNECTION_STATE.write().unwrap() = SurrealConnectionState::Connected;
|
|
||||||
} else {
|
|
||||||
log::log("surreal", "ERROR", "Failed to set SurrealDB client");
|
|
||||||
set_failure_reason("Failed to set SurrealDB client".to_string());
|
|
||||||
*SURREAL_CONNECTION_STATE.write().unwrap() = SurrealConnectionState::Failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*SURREAL_DB.write().unwrap() = Some(Arc::new(db));
|
||||||
|
log::log("surreal", "INFO", "Connected to SurrealDB server");
|
||||||
|
*SURREAL_CONNECTION_STATE.write().unwrap() = SurrealConnectionState::Connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_failure_reason(reason: String) {
|
fn set_failure_reason(reason: String) {
|
||||||
*SURREAL_FAILURE_REASON.write().unwrap() = Some(reason);
|
*SURREAL_FAILURE_REASON.write().unwrap() = Some(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_current_generation(generation: u64) -> bool {
|
||||||
|
SURREAL_INIT_GENERATION.load(Ordering::SeqCst) == generation
|
||||||
|
}
|
||||||
|
|
||||||
fn failure_reason() -> String {
|
fn failure_reason() -> String {
|
||||||
SURREAL_FAILURE_REASON
|
SURREAL_FAILURE_REASON
|
||||||
.read()
|
.read()
|
||||||
@ -136,8 +159,8 @@ async fn connect(config: SurrealConfig) -> Result<SurrealDb, String> {
|
|||||||
Ok(db)
|
Ok(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn client() -> Result<&'static SurrealDb, String> {
|
pub async fn client() -> Result<Arc<SurrealDb>, String> {
|
||||||
if let Some(db) = SURREAL_DB.get() {
|
if let Some(db) = SURREAL_DB.read().unwrap().clone() {
|
||||||
return Ok(db);
|
return Ok(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,9 +171,9 @@ pub async fn client() -> Result<&'static SurrealDb, String> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_client() -> Result<&'static SurrealDb, String> {
|
async fn wait_for_client() -> Result<Arc<SurrealDb>, String> {
|
||||||
loop {
|
loop {
|
||||||
if let Some(db) = SURREAL_DB.get() {
|
if let Some(db) = SURREAL_DB.read().unwrap().clone() {
|
||||||
return Ok(db);
|
return Ok(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +202,17 @@ pub fn status() -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn group() -> Group {
|
pub fn reconnect() -> String {
|
||||||
Group::new().command("status", status)
|
let surreal_config = config::load().surreal.clone();
|
||||||
|
prepare();
|
||||||
|
RUNTIME.spawn(async move {
|
||||||
|
initialize(surreal_config).await;
|
||||||
|
});
|
||||||
|
"reconnect initiated".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn group() -> Group {
|
||||||
|
Group::new()
|
||||||
|
.command("status", status)
|
||||||
|
.command("reconnect", reconnect)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user