Improve Redis fail-fast behavior and resilient store initialization
This commit is contained in:
parent
6c8490f299
commit
a373943eca
@ -52,6 +52,7 @@ PREP_RECOMPILE_END;
|
||||
|
||||
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Actor] Empty/Invalid UID!" };
|
||||
|
||||
GVAR(ActorStore) call ["snapshot", [_uid]];
|
||||
private _finalData = GVAR(ActorStore) call ["save", [GVAR(Registry), "actor:update", _uid]];
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
|
||||
|
||||
@ -114,15 +114,22 @@ GVAR(ActorBaseStore) = compileFinal createHashMapFromArray [
|
||||
["init", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _cached = GVAR(Registry) getOrDefault [_uid, nil];
|
||||
if !(isNil { _cached }) exitWith { _cached };
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _cached = GVAR(Registry) getOrDefault [_uid, nil];
|
||||
if !(isNil { _cached }) exitWith { [CRPC(actor,responseInitActor), [_cached], _player] call CFUNC(targetEvent); _cached };
|
||||
|
||||
["actor:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to check if actor %1 exists!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to check if actor %1 exists! Using fallback actor.", _uid]] call EFUNC(common,log);
|
||||
|
||||
private _fallbackActor = GVAR(ActorModel) call ["fromPlayer", [_player]];
|
||||
_fallbackActor set ["uid", _uid];
|
||||
_fallbackActor = GVAR(ActorModel) call ["migrate", [_fallbackActor]];
|
||||
|
||||
GVAR(Registry) set [_uid, _fallbackActor];
|
||||
[CRPC(actor,responseInitActor), [_fallbackActor], _player] call CFUNC(targetEvent);
|
||||
|
||||
_fallbackActor
|
||||
};
|
||||
|
||||
private _finalActor = createHashMap;
|
||||
@ -137,8 +144,13 @@ GVAR(ActorBaseStore) = compileFinal createHashMapFromArray [
|
||||
private _json = _self call ["toJSON", [_finalActor]];
|
||||
["actor:create", [_uid, _json]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to create actor %1!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to create actor %1! Using fallback actor.", _uid]] call EFUNC(common,log);
|
||||
|
||||
_finalActor = GVAR(ActorModel) call ["migrate", [_finalActor]];
|
||||
GVAR(Registry) set [_uid, _finalActor];
|
||||
[CRPC(actor,responseInitActor), [_finalActor], _player] call CFUNC(targetEvent);
|
||||
|
||||
_finalActor
|
||||
};
|
||||
|
||||
["INFO", format ["Created new actor for %1", _uid]] call EFUNC(common,log);
|
||||
@ -148,6 +160,36 @@ GVAR(ActorBaseStore) = compileFinal createHashMapFromArray [
|
||||
GVAR(Registry) set [_uid, _finalActor];
|
||||
|
||||
[CRPC(actor,responseInitActor), [_finalActor], _player] call CFUNC(targetEvent);
|
||||
_finalActor
|
||||
}],
|
||||
["snapshot", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _existing = GVAR(Registry) getOrDefault [_uid, createHashMap];
|
||||
private _finalActor = +_existing;
|
||||
|
||||
if (_finalActor isEqualTo createHashMap) then {
|
||||
_finalActor = GVAR(ActorModel) call ["defaults", []];
|
||||
_finalActor set ["uid", _uid];
|
||||
};
|
||||
|
||||
if (_player isNotEqualTo objNull) then {
|
||||
_finalActor set ["uid", _uid];
|
||||
_finalActor set ["name", name _player];
|
||||
_finalActor set ["position", getPosASL _player];
|
||||
_finalActor set ["direction", getDir _player];
|
||||
_finalActor set ["stance", stance _player];
|
||||
_finalActor set ["rank", rank _player];
|
||||
_finalActor set ["state", lifeState _player];
|
||||
_finalActor set ["loadout", getUnitLoadout _player];
|
||||
} else {
|
||||
["WARNING", format ["No player object found for %1 during actor snapshot, using cached values.", _uid]] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
_finalActor = GVAR(ActorModel) call ["migrate", [_finalActor]];
|
||||
GVAR(Registry) set [_uid, _finalActor];
|
||||
|
||||
_finalActor
|
||||
}]
|
||||
];
|
||||
|
||||
@ -102,15 +102,24 @@ GVAR(BankBaseStore) = compileFinal createHashMapFromArray [
|
||||
["init", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _cached = GVAR(Registry) getOrDefault [_uid, nil];
|
||||
if !(isNil { _cached }) exitWith { _cached };
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _cached = GVAR(Registry) getOrDefault [_uid, nil];
|
||||
if !(isNil { _cached }) exitWith { [CRPC(bank,responseInitBank), [_cached], _player] call CFUNC(targetEvent); _cached };
|
||||
|
||||
["bank:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to check if bank account %1 exists!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to check if bank account %1 exists! Using fallback account.", _uid]] call EFUNC(common,log);
|
||||
|
||||
private _fallbackAccount = GVAR(BankModel) call ["fromPlayer", [_player]];
|
||||
_fallbackAccount set ["uid", _uid];
|
||||
|
||||
private _regEntry = createHashMapFromArray [["uid", _uid], ["name", (name _player)]];
|
||||
GVAR(IndexRegistry) set [_uid, _regEntry];
|
||||
|
||||
GVAR(Registry) set [_uid, _fallbackAccount];
|
||||
[CRPC(bank,responseInitBank), [_fallbackAccount], _player] call CFUNC(targetEvent);
|
||||
|
||||
_fallbackAccount
|
||||
};
|
||||
|
||||
private _finalAccount = createHashMap;
|
||||
@ -125,8 +134,15 @@ GVAR(BankBaseStore) = compileFinal createHashMapFromArray [
|
||||
private _json = _self call ["toJSON", [_finalAccount]];
|
||||
["bank:create", [_uid, _json]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to create bank account %1!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to create bank account %1! Using fallback account.", _uid]] call EFUNC(common,log);
|
||||
|
||||
private _regEntry = createHashMapFromArray [["uid", _uid], ["name", (name _player)]];
|
||||
GVAR(IndexRegistry) set [_uid, _regEntry];
|
||||
|
||||
GVAR(Registry) set [_uid, _finalAccount];
|
||||
[CRPC(bank,responseInitBank), [_finalAccount], _player] call CFUNC(targetEvent);
|
||||
|
||||
_finalAccount
|
||||
};
|
||||
|
||||
["INFO", format ["Created new bank account for %1", _uid]] call EFUNC(common,log);
|
||||
|
||||
@ -25,6 +25,27 @@
|
||||
params [["_function", "", [""]], ["_arguments", [], [[]]]];
|
||||
|
||||
["INFO", format ["Calling function: %1", _function], nil, nil] call EFUNC(common,log);
|
||||
|
||||
private _functionLower = toLower _function;
|
||||
private _requiresRedis = !(_functionLower in ["status", "version"])
|
||||
&& (_functionLower find "icom:" == 0)
|
||||
&& (_functionLower find "terrain:" == 0);
|
||||
|
||||
if (_requiresRedis) then {
|
||||
("forge_server" callExtension ["status", []]) params ["_redisStatus", "_statusExtCode", "_statusArmaCode"];
|
||||
|
||||
private _statusSuccess = (_statusExtCode == 0) && (_statusArmaCode == 0 || _statusArmaCode == 301);
|
||||
if (!_statusSuccess) exitWith {
|
||||
["WARNING", "Unable to determine Redis status before extension call", nil, nil] call EFUNC(common,log);
|
||||
["Error: Redis status check failed", false]
|
||||
};
|
||||
|
||||
if (_redisStatus != "connected") exitWith {
|
||||
["WARNING", format ["Blocked extension call '%1' because Redis status is '%2'", _function, _redisStatus], nil, nil] call EFUNC(common,log);
|
||||
[format ["Error: Redis is %1", _redisStatus], false]
|
||||
};
|
||||
};
|
||||
|
||||
("forge_server" callExtension [_function, _arguments]) params ["_result", "_extCode", "_armaCode"];
|
||||
|
||||
private _success = true;
|
||||
|
||||
@ -32,13 +32,19 @@ GVAR(GarageBaseStore) = compileFinal createHashMapFromArray [
|
||||
["init", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _cached = GVAR(Registry) getOrDefault [_uid, nil];
|
||||
if !(isNil { _cached }) exitWith { _cached };
|
||||
if !(isNil { _cached }) exitWith { [CRPC(garage,responseInitGarage), [_cached], _player] call CFUNC(targetEvent); _cached };
|
||||
|
||||
["garage:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to check if garage %1 exists!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to check if garage %1 exists! Using fallback garage.", _uid]] call EFUNC(common,log);
|
||||
|
||||
private _fallbackGarage = createHashMap;
|
||||
GVAR(Registry) set [_uid, _fallbackGarage];
|
||||
[CRPC(garage,responseInitGarage), [_fallbackGarage], _player] call CFUNC(targetEvent);
|
||||
|
||||
_fallbackGarage
|
||||
};
|
||||
|
||||
private _finalGarage = createHashMap;
|
||||
@ -49,15 +55,17 @@ GVAR(GarageBaseStore) = compileFinal createHashMapFromArray [
|
||||
} else {
|
||||
["garage:create", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to create garage for %1!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to create garage for %1! Using fallback garage.", _uid]] call EFUNC(common,log);
|
||||
|
||||
GVAR(Registry) set [_uid, _finalGarage];
|
||||
[CRPC(garage,responseInitGarage), [_finalGarage], _player] call CFUNC(targetEvent);
|
||||
|
||||
_finalGarage
|
||||
};
|
||||
|
||||
["INFO", format ["Created new garage for %1", _uid]] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
|
||||
GVAR(Registry) set [_uid, _finalGarage];
|
||||
[CRPC(garage,responseInitGarage), [_finalGarage], _player] call CFUNC(targetEvent);
|
||||
|
||||
|
||||
@ -48,13 +48,22 @@ GVAR(VGBaseStore) = compileFinal createHashMapFromArray [
|
||||
["init", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _cached = GVAR(VGRegistry) getOrDefault [_uid, nil];
|
||||
if !(isNil { _cached }) exitWith { _cached };
|
||||
if !(isNil { _cached }) exitWith {
|
||||
[CRPC(garage,responseInitVG), [_cached], _player] call CFUNC(targetEvent);
|
||||
_cached
|
||||
};
|
||||
|
||||
["owned:garage:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to check if virtual garage %1 exists!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to check if virtual garage %1 exists! Using fallback virtual garage.", _uid]] call EFUNC(common,log);
|
||||
|
||||
private _fallbackVGarage = GVAR(VGarageModel) call ["defaults", []];
|
||||
GVAR(VGRegistry) set [_uid, _fallbackVGarage];
|
||||
[CRPC(garage,responseInitVG), [_fallbackVGarage], _player] call CFUNC(targetEvent);
|
||||
|
||||
_fallbackVGarage
|
||||
};
|
||||
|
||||
private _finalVGarage = createHashMap;
|
||||
@ -67,15 +76,17 @@ GVAR(VGBaseStore) = compileFinal createHashMapFromArray [
|
||||
|
||||
["owned:garage:create", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to create virtual garage for %1!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to create virtual garage for %1! Using fallback virtual garage.", _uid]] call EFUNC(common,log);
|
||||
|
||||
GVAR(VGRegistry) set [_uid, _finalVGarage];
|
||||
[CRPC(garage,responseInitVG), [_finalVGarage], _player] call CFUNC(targetEvent);
|
||||
|
||||
_finalVGarage
|
||||
};
|
||||
|
||||
["INFO", format ["Created new virtual garage for %1", _uid]] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
|
||||
GVAR(VGRegistry) set [_uid, _finalVGarage];
|
||||
[CRPC(garage,responseInitVG), [_finalVGarage], _player] call CFUNC(targetEvent);
|
||||
|
||||
|
||||
@ -32,13 +32,19 @@ GVAR(LockerBaseStore) = compileFinal createHashMapFromArray [
|
||||
["init", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _cached = GVAR(Registry) getOrDefault [_uid, nil];
|
||||
if !(isNil { _cached }) exitWith { _cached };
|
||||
if !(isNil { _cached }) exitWith { [CRPC(locker,responseInitLocker), [_cached], _player] call CFUNC(targetEvent); _cached };
|
||||
|
||||
["locker:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to check if locker %1 exists!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to check if locker %1 exists! Using fallback locker.", _uid]] call EFUNC(common,log);
|
||||
|
||||
private _fallbackLocker = createHashMap;
|
||||
GVAR(Registry) set [_uid, _fallbackLocker];
|
||||
[CRPC(locker,responseInitLocker), [_fallbackLocker], _player] call CFUNC(targetEvent);
|
||||
|
||||
_fallbackLocker
|
||||
};
|
||||
|
||||
private _finalLocker = createHashMap;
|
||||
@ -49,15 +55,17 @@ GVAR(LockerBaseStore) = compileFinal createHashMapFromArray [
|
||||
} else {
|
||||
["locker:create", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to create locker for %1!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to create locker for %1! Using fallback locker.", _uid]] call EFUNC(common,log);
|
||||
|
||||
GVAR(Registry) set [_uid, _finalLocker];
|
||||
[CRPC(locker,responseInitLocker), [_finalLocker], _player] call CFUNC(targetEvent);
|
||||
|
||||
_finalLocker
|
||||
};
|
||||
|
||||
["INFO", format ["Created new locker for %1", _uid]] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
|
||||
GVAR(Registry) set [_uid, _finalLocker];
|
||||
[CRPC(locker,responseInitLocker), [_finalLocker], _player] call CFUNC(targetEvent);
|
||||
|
||||
|
||||
@ -46,13 +46,22 @@ GVAR(VABaseStore) = compileFinal createHashMapFromArray [
|
||||
["init", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _cached = GVAR(VARegistry) getOrDefault [_uid, nil];
|
||||
if !(isNil { _cached }) exitWith { _cached };
|
||||
if !(isNil { _cached }) exitWith {
|
||||
[CRPC(locker,responseInitVA), [_cached], _player] call CFUNC(targetEvent);
|
||||
_cached
|
||||
};
|
||||
|
||||
["owned:locker:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to check if virtual arsenal %1 exists!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to check if virtual arsenal %1 exists! Using fallback virtual arsenal.", _uid]] call EFUNC(common,log);
|
||||
|
||||
private _fallbackVArsenal = GVAR(VArsenalModel) call ["defaults", []];
|
||||
GVAR(VARegistry) set [_uid, _fallbackVArsenal];
|
||||
[CRPC(locker,responseInitVA), [_fallbackVArsenal], _player] call CFUNC(targetEvent);
|
||||
|
||||
_fallbackVArsenal
|
||||
};
|
||||
|
||||
private _finalVArsenal = createHashMap;
|
||||
@ -65,15 +74,17 @@ GVAR(VABaseStore) = compileFinal createHashMapFromArray [
|
||||
|
||||
["owned:locker:create", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to create virtual arsenal for %1!", _uid]] call EFUNC(common,log);
|
||||
createHashMap
|
||||
["ERROR", format ["Failed to create virtual arsenal for %1! Using fallback virtual arsenal.", _uid]] call EFUNC(common,log);
|
||||
|
||||
GVAR(VARegistry) set [_uid, _finalVArsenal];
|
||||
[CRPC(locker,responseInitVA), [_finalVArsenal], _player] call CFUNC(targetEvent);
|
||||
|
||||
_finalVArsenal
|
||||
};
|
||||
|
||||
["INFO", format ["Created new virtual arsenal for %1", _uid]] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
|
||||
GVAR(VARegistry) set [_uid, _finalVArsenal];
|
||||
[CRPC(locker,responseInitVA), [_finalVArsenal], _player] call CFUNC(targetEvent);
|
||||
|
||||
|
||||
@ -7,12 +7,11 @@ PREP_RECOMPILE_END;
|
||||
// private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)];
|
||||
|
||||
[QGVAR(requestInitOrg), {
|
||||
params [["_uid", "", [""]], ["_org", createHashMap, [createHashMap]]];
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Org] Empty/Invalid UID!" };
|
||||
if (_org isEqualTo createHashMap) exitWith { diag_log "[FORGE:Server:Org] Empty/Invalid Org data!" };
|
||||
|
||||
GVAR(OrgStore) call ["init", [_uid, _org]];
|
||||
GVAR(OrgStore) call ["init", [_uid]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(requestGetOrg), {
|
||||
|
||||
@ -81,7 +81,18 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
["org:exists", ["default"]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", "Failed to check for default org!"] call EFUNC(common,log);
|
||||
createHashMap;
|
||||
|
||||
private _fallbackDefaultOrg = createHashMapFromArray [
|
||||
["id", "default"],
|
||||
["owner", "server"],
|
||||
["name", "Forge Dynamics"],
|
||||
["funds", 200000],
|
||||
["reputation", 0],
|
||||
["members", createHashMap]
|
||||
];
|
||||
GVAR(Registry) set ["default", _fallbackDefaultOrg];
|
||||
|
||||
_fallbackDefaultOrg
|
||||
};
|
||||
|
||||
private _finalOrg = createHashMap;
|
||||
@ -104,23 +115,39 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
["init", compileFinal {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
private _actor = EGVAR(actor,Registry) get _uid;
|
||||
private _orgID = _actor get "organization";
|
||||
if (_orgID isEqualTo "") then { _orgID = "default" };
|
||||
|
||||
private _cached = GVAR(Registry) getOrDefault [_orgID, nil];
|
||||
if !(isNil { _cached }) exitWith { _cached };
|
||||
if !(isNil { _cached }) exitWith { [CRPC(org,responseInitOrg), [_cached], _player] call CFUNC(targetEvent); _cached };
|
||||
|
||||
["org:exists", [_orgID]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||
if !(_isSuccess) exitWith {
|
||||
["ERROR", format ["Failed to check for org %1!", _orgID]] call EFUNC(common,log);
|
||||
createHashMap;
|
||||
["ERROR", format ["Failed to check for org %1! Using fallback org.", _orgID]] call EFUNC(common,log);
|
||||
|
||||
private _fallbackOrg = GVAR(Registry) getOrDefault ["default", createHashMapFromArray [
|
||||
["id", "default"],
|
||||
["owner", "server"],
|
||||
["name", "Forge Dynamics"],
|
||||
["funds", 200000],
|
||||
["reputation", 0],
|
||||
["members", createHashMap]
|
||||
]];
|
||||
|
||||
private _entry = createHashMapFromArray [["orgID", _orgID]];
|
||||
GVAR(IndexRegistry) set [_uid, _entry];
|
||||
|
||||
GVAR(Registry) set [_orgID, _fallbackOrg, true];
|
||||
[CRPC(org,responseInitOrg), [_fallbackOrg], _player] call CFUNC(targetEvent);
|
||||
|
||||
_fallbackOrg;
|
||||
};
|
||||
|
||||
private _finalOrg = createHashMap;
|
||||
private _finalMembers = createHashMap;
|
||||
// private _finalAssets = createHashMap;
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
|
||||
if (_result == "true") then {
|
||||
_finalOrg = _self call ["fetch", ["org:get", _orgID]];
|
||||
|
||||
@ -16,6 +16,9 @@ db = 0 # Redis database number (0-15)
|
||||
max_connections = 10 # Maximum number of connections in pool
|
||||
min_connections = 2 # Minimum number of idle connections
|
||||
idle_timeout = 60 # Idle connection timeout in seconds
|
||||
connect_timeout_ms = 2000 # Pool connect timeout in milliseconds
|
||||
pool_get_timeout_ms = 2000 # Pool checkout timeout in milliseconds
|
||||
command_timeout_ms = 2000 # Redis command timeout in milliseconds
|
||||
|
||||
# Example configurations for different environments:
|
||||
|
||||
@ -33,3 +36,6 @@ idle_timeout = 60 # Idle connection timeout in seconds
|
||||
# max_connections = 20
|
||||
# min_connections = 5
|
||||
# idle_timeout = 30
|
||||
# connect_timeout_ms = 5000
|
||||
# pool_get_timeout_ms = 5000
|
||||
# command_timeout_ms = 5000
|
||||
|
||||
@ -16,6 +16,9 @@ db = 0 # Redis database number (0-15)
|
||||
max_connections = 10 # Maximum number of connections in pool
|
||||
min_connections = 2 # Minimum number of idle connections
|
||||
idle_timeout = 60 # Idle connection timeout in seconds
|
||||
connect_timeout_ms = 2000 # Pool connect timeout in milliseconds
|
||||
pool_get_timeout_ms = 2000 # Pool checkout timeout in milliseconds
|
||||
command_timeout_ms = 2000 # Redis command timeout in milliseconds
|
||||
|
||||
# Example configurations for different environments:
|
||||
|
||||
@ -33,3 +36,6 @@ idle_timeout = 60 # Idle connection timeout in seconds
|
||||
# max_connections = 20
|
||||
# min_connections = 5
|
||||
# idle_timeout = 30
|
||||
# connect_timeout_ms = 5000
|
||||
# pool_get_timeout_ms = 5000
|
||||
# command_timeout_ms = 5000
|
||||
|
||||
@ -241,13 +241,12 @@ pub fn actor_exists(call_context: CallContext, key: String) -> String {
|
||||
|
||||
match ACTOR_SERVICE.actor_exists(resolved_uid.clone()) {
|
||||
Ok(exists) => {
|
||||
let result = if exists { "true" } else { "false" };
|
||||
log(
|
||||
"actor",
|
||||
"DEBUG",
|
||||
&format!("Actor '{}' exists: {}", resolved_uid, result),
|
||||
&format!("Actor '{}' exists: {}", resolved_uid, exists),
|
||||
);
|
||||
result.to_string()
|
||||
exists.to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
log(
|
||||
|
||||
@ -222,11 +222,7 @@ pub fn bank_exists(call_context: CallContext, key: String) -> String {
|
||||
|
||||
let resolved_uid = match resolve_uid(&key, &call_context) {
|
||||
Some(uid) => {
|
||||
log(
|
||||
"bank",
|
||||
"DEBUG",
|
||||
&format!("Resolved UID for existence check: {}", uid),
|
||||
);
|
||||
log("bank", "DEBUG", &format!("Resolved UID: {}", uid));
|
||||
uid
|
||||
}
|
||||
None => {
|
||||
@ -241,13 +237,12 @@ pub fn bank_exists(call_context: CallContext, key: String) -> String {
|
||||
|
||||
match BANK_SERVICE.bank_exists(resolved_uid.clone()) {
|
||||
Ok(exists) => {
|
||||
let result = if exists { "true" } else { "false" };
|
||||
log(
|
||||
"bank",
|
||||
"DEBUG",
|
||||
&format!("Bank '{}' exists: {}", resolved_uid, result),
|
||||
&format!("Bank '{}' exists: {}", resolved_uid, exists),
|
||||
);
|
||||
result.to_string()
|
||||
exists.to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
log(
|
||||
|
||||
@ -518,9 +518,12 @@ pub fn garage_exists(call_context: CallContext, key: String) -> String {
|
||||
uid
|
||||
}
|
||||
None => {
|
||||
let error_msg = format!("Error: Failed to resolve UID for key: {}", key);
|
||||
log("garage", "ERROR", &error_msg);
|
||||
return error_msg;
|
||||
log(
|
||||
"garage",
|
||||
"ERROR",
|
||||
&format!("Failed to resolve UID for key: {}", key),
|
||||
);
|
||||
return "false".to_string();
|
||||
}
|
||||
};
|
||||
|
||||
@ -529,18 +532,17 @@ pub fn garage_exists(call_context: CallContext, key: String) -> String {
|
||||
log(
|
||||
"garage",
|
||||
"DEBUG",
|
||||
&format!("Garage exists for '{}': {}", resolved_uid, exists),
|
||||
&format!("Garage '{}' exists: {}", resolved_uid, exists),
|
||||
);
|
||||
exists.to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
let error_msg = format!("Error: {}", e);
|
||||
log(
|
||||
"garage",
|
||||
"ERROR",
|
||||
&format!("Failed to check garage existence '{}': {}", resolved_uid, e),
|
||||
&format!("Failed to check if garage '{}' exists: {}", resolved_uid, e),
|
||||
);
|
||||
error_msg
|
||||
"false".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,9 +473,12 @@ pub fn locker_exists(call_context: CallContext, key: String) -> String {
|
||||
uid
|
||||
}
|
||||
None => {
|
||||
let error_msg = format!("Error: Failed to resolve UID for key: {}", key);
|
||||
log("locker", "ERROR", &error_msg);
|
||||
return error_msg;
|
||||
log(
|
||||
"locker",
|
||||
"ERROR",
|
||||
&format!("Failed to resolve UID for key: {}", key),
|
||||
);
|
||||
return "false".to_string();
|
||||
}
|
||||
};
|
||||
|
||||
@ -483,13 +486,12 @@ pub fn locker_exists(call_context: CallContext, key: String) -> String {
|
||||
Ok(exists) => {
|
||||
log(
|
||||
"locker",
|
||||
"INFO",
|
||||
&format!("Locker exists for: {}", resolved_uid),
|
||||
"DEBUG",
|
||||
&format!("Locker '{}' exists: {}", resolved_uid, exists),
|
||||
);
|
||||
exists.to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
let error_msg = format!("Error: {}", e);
|
||||
log(
|
||||
"locker",
|
||||
"ERROR",
|
||||
@ -498,7 +500,7 @@ pub fn locker_exists(call_context: CallContext, key: String) -> String {
|
||||
resolved_uid, e
|
||||
),
|
||||
);
|
||||
error_msg
|
||||
"false".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use super::config::RedisConfig;
|
||||
use bb8_redis::{RedisConnectionManager, bb8};
|
||||
use std::error::Error;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Redis connection pool type alias.
|
||||
pub type RedisClient = bb8::Pool<RedisConnectionManager>;
|
||||
@ -33,10 +34,14 @@ pub async fn create_redis_pool(
|
||||
// Configure idle connection timeout if specified
|
||||
// This prevents keeping stale connections that might be closed by the server
|
||||
if let Some(idle_timeout) = config.idle_timeout {
|
||||
use std::time::Duration;
|
||||
pool_builder = pool_builder.idle_timeout(Some(Duration::from_secs(idle_timeout)));
|
||||
}
|
||||
|
||||
// Bound connection acquisition from the pool so game thread calls fail fast
|
||||
if let Some(connect_timeout_ms) = config.connect_timeout_ms {
|
||||
pool_builder = pool_builder.connection_timeout(Duration::from_millis(connect_timeout_ms));
|
||||
}
|
||||
|
||||
// Build the final connection pool with all configured parameters
|
||||
let pool = pool_builder.build(manager).await?;
|
||||
Ok(pool)
|
||||
|
||||
@ -3,9 +3,12 @@
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::log::log;
|
||||
|
||||
static CONFIG_CACHE: OnceLock<Config> = OnceLock::new();
|
||||
|
||||
/// Main configuration structure for the entire application.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Config {
|
||||
@ -42,6 +45,12 @@ pub struct RedisConfig {
|
||||
pub min_connections: Option<usize>,
|
||||
/// Idle connection timeout in seconds
|
||||
pub idle_timeout: Option<u64>,
|
||||
/// Maximum time to wait for pool connection checkout in milliseconds
|
||||
pub pool_get_timeout_ms: Option<u64>,
|
||||
/// Maximum time to wait for individual Redis command execution in milliseconds
|
||||
pub command_timeout_ms: Option<u64>,
|
||||
/// Maximum time to wait for pool connection establishment in milliseconds
|
||||
pub connect_timeout_ms: Option<u64>,
|
||||
}
|
||||
|
||||
impl Default for RedisConfig {
|
||||
@ -56,6 +65,9 @@ impl Default for RedisConfig {
|
||||
max_connections: Some(10),
|
||||
min_connections: Some(2),
|
||||
idle_timeout: Some(60),
|
||||
pool_get_timeout_ms: Some(2000),
|
||||
command_timeout_ms: Some(2000),
|
||||
connect_timeout_ms: Some(2000),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,6 +105,8 @@ impl RedisConfig {
|
||||
|
||||
/// Loads configuration from the `config.toml` file with graceful fallback to defaults.
|
||||
pub fn load() -> Config {
|
||||
CONFIG_CACHE
|
||||
.get_or_init(|| {
|
||||
let config_path = std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|exe| {
|
||||
@ -119,4 +133,6 @@ pub fn load() -> Config {
|
||||
Config::default()
|
||||
}
|
||||
}
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
@ -4,33 +4,55 @@
|
||||
#[macro_export]
|
||||
macro_rules! redis_operation {
|
||||
($conn:ident => $operation:block) => {{
|
||||
use tokio::time::{Duration, timeout};
|
||||
use $crate::redis;
|
||||
use $crate::{CONNECTION_STATE, ConnectionState, REDIS_POOL, RUNTIME};
|
||||
|
||||
let timeout_config = redis::config::load().redis;
|
||||
let pool_get_timeout =
|
||||
Duration::from_millis(timeout_config.pool_get_timeout_ms.unwrap_or(2000));
|
||||
let command_timeout =
|
||||
Duration::from_millis(timeout_config.command_timeout_ms.unwrap_or(2000));
|
||||
let init_timeout = Duration::from_millis(timeout_config.connect_timeout_ms.unwrap_or(2000));
|
||||
|
||||
// Get the Redis connection pool (initialized at startup)
|
||||
let pool = match REDIS_POOL.get() {
|
||||
Some(pool) => pool,
|
||||
None => {
|
||||
if *CONNECTION_STATE.read().unwrap() == ConnectionState::Failed {
|
||||
return "Error: Redis connection unavailable".to_string();
|
||||
}
|
||||
|
||||
// Attempt lazy initialization if not already initialized
|
||||
let rt = &RUNTIME;
|
||||
let init_result = rt.block_on(async move {
|
||||
let cfg = redis::config::load();
|
||||
match redis::client::create_redis_pool(&cfg.redis).await {
|
||||
Ok(pool) => {
|
||||
match timeout(init_timeout, redis::client::create_redis_pool(&cfg.redis)).await
|
||||
{
|
||||
Ok(Ok(pool)) => {
|
||||
let _ = REDIS_POOL.set(pool);
|
||||
Ok(())
|
||||
}
|
||||
Err(_e) => {
|
||||
Ok(Err(_e)) => {
|
||||
let default_cfg = redis::RedisConfig::default();
|
||||
match redis::client::create_redis_pool(&default_cfg).await {
|
||||
Ok(pool) => {
|
||||
match timeout(
|
||||
init_timeout,
|
||||
redis::client::create_redis_pool(&default_cfg),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(Ok(pool)) => {
|
||||
let _ = REDIS_POOL.set(pool);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(format!("{}", e)),
|
||||
Ok(Err(e)) => Err(format!("{}", e)),
|
||||
Err(_) => {
|
||||
Err("Redis fallback initialization timed out".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => Err("Redis initialization timed out".to_string()),
|
||||
}
|
||||
});
|
||||
|
||||
match init_result {
|
||||
@ -53,13 +75,17 @@ macro_rules! redis_operation {
|
||||
let rt = &RUNTIME;
|
||||
rt.block_on(async move {
|
||||
// Acquire a connection from the pool
|
||||
let mut $conn = match pool.get().await {
|
||||
Ok(conn) => conn,
|
||||
Err(e) => return format!("Error: {}", e),
|
||||
let mut $conn = match timeout(pool_get_timeout, pool.get()).await {
|
||||
Ok(Ok(conn)) => conn,
|
||||
Ok(Err(e)) => return format!("Error: {}", e),
|
||||
Err(_) => return "Error: Redis connection checkout timed out".to_string(),
|
||||
};
|
||||
|
||||
// Execute the user-provided Redis operation
|
||||
$operation
|
||||
match timeout(command_timeout, async move { $operation }).await {
|
||||
Ok(result) => result,
|
||||
Err(_) => "Error: Redis operation timed out".to_string(),
|
||||
}
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
@ -428,9 +428,12 @@ pub fn vgarage_exists(call_context: CallContext, key: String) -> String {
|
||||
uid
|
||||
}
|
||||
None => {
|
||||
let error_msg = format!("Error: Failed to resolve UID for key: {}", key);
|
||||
log("v_garage", "ERROR", &error_msg);
|
||||
return error_msg;
|
||||
log(
|
||||
"v_garage",
|
||||
"WARN",
|
||||
&format!("Failed to resolve UID for key: {}", key),
|
||||
);
|
||||
return "false".to_string();
|
||||
}
|
||||
};
|
||||
|
||||
@ -438,22 +441,21 @@ pub fn vgarage_exists(call_context: CallContext, key: String) -> String {
|
||||
Ok(exists) => {
|
||||
log(
|
||||
"v_garage",
|
||||
"INFO",
|
||||
&format!("Virtual garage exists for: {}", resolved_uid),
|
||||
"DEBUG",
|
||||
&format!("Virtual garage '{}' exists: {}", resolved_uid, exists),
|
||||
);
|
||||
exists.to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
let error_msg = format!("Error: {}", e);
|
||||
log(
|
||||
"v_garage",
|
||||
"ERROR",
|
||||
&format!(
|
||||
"Failed to check if virtual garage exists for '{}': {}",
|
||||
"Failed to check if virtual garage '{}' exists: {}",
|
||||
resolved_uid, e
|
||||
),
|
||||
);
|
||||
error_msg
|
||||
"false".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,9 +424,12 @@ pub fn vlocker_exists(call_context: CallContext, key: String) -> String {
|
||||
uid
|
||||
}
|
||||
None => {
|
||||
let error_msg = format!("Error: Failed to resolve UID for key: {}", key);
|
||||
log("v_locker", "ERROR", &error_msg);
|
||||
return error_msg;
|
||||
log(
|
||||
"v_locker",
|
||||
"WARN",
|
||||
&format!("Failed to resolve UID for key: {}", key),
|
||||
);
|
||||
return "false".to_string();
|
||||
}
|
||||
};
|
||||
|
||||
@ -434,22 +437,21 @@ pub fn vlocker_exists(call_context: CallContext, key: String) -> String {
|
||||
Ok(exists) => {
|
||||
log(
|
||||
"v_locker",
|
||||
"INFO",
|
||||
&format!("Virtual locker exists for: {}", resolved_uid),
|
||||
"DEBUG",
|
||||
&format!("Virtual locker '{}' exists: {}", resolved_uid, exists),
|
||||
);
|
||||
exists.to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
let error_msg = format!("Error: {}", e);
|
||||
log(
|
||||
"v_locker",
|
||||
"ERROR",
|
||||
&format!(
|
||||
"Failed to check if virtual locker exists for '{}': {}",
|
||||
"Failed to check if virtual locker '{}' exists: {}",
|
||||
resolved_uid, e
|
||||
),
|
||||
);
|
||||
error_msg
|
||||
"false".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user