Skip to content

Commit 23d816e

Browse files
committed
[Node] fix process bot restart issues
1 parent 166af3f commit 23d816e

10 files changed

Lines changed: 1023 additions & 66 deletions

File tree

octobot/storage/process_bot_state_dumper.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@ async def _write_state_file_async(
7373
) -> None:
7474
now = time.time()
7575
state = process_bot_state_import.ProcessBotState(
76-
metadata=process_bot_state_import.Metadata(updated_at=now, next_updated_at=now + interval),
76+
metadata=process_bot_state_import.Metadata(
77+
updated_at=now,
78+
next_updated_at=now + interval,
79+
pid=os.getpid(),
80+
),
7781
exchange_account_elements=_synced_exchange_account_elements_for_first_trading_exchange(
7882
bot,
7983
),

packages/flow/octobot_flow/entities/accounts/process_bot_state.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
@dataclasses.dataclass
1111
class Metadata(octobot_commons.dataclasses.MinimizableDataclass):
1212
"""
13-
Timestamps written with process bot state dumps; used for file-based liveness checks.
13+
Timestamps and child PID written with process bot state dumps. Liveness checks use
14+
updated_at / next_updated_at only; pid is the authoritative child PID for parent binding
15+
after restarts.
1416
"""
1517

1618
updated_at: float = 0.0
1719
next_updated_at: float = 0.0
20+
pid: int = 0
1821

1922

2023
@dataclasses.dataclass

packages/flow/octobot_flow/environment.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1+
import typing
2+
13
import octobot.constants # will load .env file and init constants
24

35
import octobot_flow.repositories.community
46
import octobot_trading.constants
57

8+
_EXECUTOR_ID: typing.Optional[str] = None
9+
10+
11+
def register_executor_id(executor_id: str) -> None:
12+
global _EXECUTOR_ID
13+
_EXECUTOR_ID = executor_id
14+
15+
16+
def get_executor_id() -> typing.Optional[str]:
17+
return _EXECUTOR_ID
18+
619

720
def initialize_environment(allow_funds_transfer: bool = False) -> None:
821
octobot_flow.repositories.community.initialize_community_authentication()

packages/flow/octobot_flow/logic/dsl/dsl_executor.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import octobot_evaluators.evaluators as evaluators
1313

1414
import octobot_flow.entities
15+
import octobot_flow.environment
1516
import octobot_flow.errors
1617
import octobot_flow.enums
1718
import octobot_flow.logic.dsl.action_error_util
@@ -24,21 +25,23 @@
2425
import tentacles.Meta.DSL_operators.octobot_process_operators.octobot_process_ops as octobot_process_ops
2526

2627

27-
2828
class DSLExecutor(AbstractActionExecutor):
2929
def __init__(
3030
self,
3131
profile_data: octobot_commons.profiles.ProfileData,
3232
exchange_manager: typing.Optional[octobot_trading.exchanges.ExchangeManager],
3333
dsl_script: typing.Optional[str],
3434
dependencies: typing.Optional[octobot_commons.signals.SignalDependencies] = None,
35+
executor_id: typing.Optional[str] = None,
3536
):
3637
super().__init__()
3738
self._exchange_manager = exchange_manager
3839
self._dependencies = dependencies
3940
self._dependencies_config: dict = profile_data.to_profile("").config
4041
self._interpreter_signals: octobot_commons.dsl_interpreter.OperatorSignals = None # type: ignore (reset when interpreter is created)
41-
self._interpreter: octobot_commons.dsl_interpreter.Interpreter = self._create_interpreter(None)
42+
self._interpreter: octobot_commons.dsl_interpreter.Interpreter = self._create_interpreter(
43+
None, executor_id
44+
)
4245
if dsl_script:
4346
self._interpreter.prepare(dsl_script)
4447

@@ -49,7 +52,15 @@ def _get_matrix_id(self) -> typing.Optional[str]:
4952

5053
def get_flow_operator_classes(
5154
self,
55+
executor_id: typing.Optional[str] = None,
5256
) -> list[typing.Type[octobot_commons.dsl_interpreter.Operator]]:
57+
resolved_executor_id = (
58+
executor_id or octobot_flow.environment.get_executor_id()
59+
)
60+
if not resolved_executor_id:
61+
raise octobot_flow.errors.MissingDSLExecutorDependencyError(
62+
"executor_id is required for run_octobot_process"
63+
)
5364
return (
5465
octobot_commons.dsl_interpreter.get_all_operators()
5566
+ dsl_operators.create_ohlcv_operators(self._exchange_manager, None, None)
@@ -74,16 +85,19 @@ def get_flow_operator_classes(
7485
copier_trading_mode=None,
7586
)
7687
+ octobot_process_ops.create_octobot_process_operators(
77-
self._interpreter_signals
88+
self._interpreter_signals,
89+
resolved_executor_id,
7890
)
7991
) # type: ignore (list[type[Operator]])
8092

8193
def _create_interpreter(
82-
self, previous_execution_result: typing.Optional[dict]
94+
self,
95+
previous_execution_result: typing.Optional[dict],
96+
executor_id: typing.Optional[str] = None,
8397
) -> octobot_commons.dsl_interpreter.Interpreter:
8498
self._interpreter_signals = octobot_commons.dsl_interpreter.OperatorSignals()
8599
return octobot_commons.dsl_interpreter.Interpreter(
86-
self.get_flow_operator_classes()
100+
self.get_flow_operator_classes(executor_id)
87101
)
88102

89103
def get_dependencies(self) -> list[
@@ -110,7 +124,8 @@ async def execute_action(
110124
] = None,
111125
) -> octobot_commons.dsl_interpreter.DSLCallResult:
112126
self._interpreter = self._create_interpreter(
113-
action.previous_execution_result
127+
action.previous_execution_result,
128+
None,
114129
)
115130
expression = action.get_resolved_dsl_script()
116131
try:

packages/flow/tests/functionnal_tests/octobot_process_actions/octobot_process_functional_shared.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import octobot_flow.jobs
1414
import octobot_flow.entities
15+
import octobot_flow.environment
1516
import octobot_flow.enums
1617
import tests.functionnal_tests as functionnal_tests
1718
import tests.functionnal_tests.tentacle_test_configs as tentacle_test_configs
@@ -213,6 +214,12 @@ def _tracked(*args: typing.Any, **kwargs: typing.Any) -> typing.Any:
213214
return _tracked
214215

215216

217+
@pytest.fixture(autouse=True)
218+
def register_functional_executor_id():
219+
octobot_flow.environment.register_executor_id("func-test-executor")
220+
yield
221+
222+
216223
@pytest.fixture
217224
def init_action():
218225
# Automation apply_configuration: seed automation state to match expected exchange + portfolio.

packages/node/octobot_node/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# You should have received a copy of the GNU General Public
1515
# License along with OctoBot. If not, see <https://www.gnu.org/licenses/>.
1616
import os
17+
import uuid
1718

1819
try:
1920
import octobot.constants as octobot_constants
@@ -67,3 +68,5 @@
6768
)
6869

6970
DEFAULT_PORTFOLIO_VALUATION_UNIT = "USDT"
71+
72+
SCHEDULER_EXECUTOR_ID = str(uuid.uuid4()) # unique for each worker

packages/node/octobot_node/scheduler/octobot_flow_client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import octobot_commons.dataclasses
2222

23+
import octobot_node.constants
2324
import octobot_node.errors as errors
2425
import octobot_node.scheduler.workflows_util as workflows_util
2526

@@ -33,6 +34,9 @@
3334

3435
# ensure environment is initialized
3536
octobot_flow.environment.initialize_environment(True)
37+
octobot_flow.environment.register_executor_id(
38+
octobot_node.constants.SCHEDULER_EXECUTOR_ID
39+
)
3640

3741
except ImportError:
3842
pass # OctoBot Flow is not available

packages/node/octobot_node/scheduler/scheduler.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
_BASE_CONFIG = dbos.DBOSConfig(
4949
name=DEFAULT_NAME,
5050
max_executor_threads=octobot_node.config.settings.SCHEDULER_MAX_EXECUTOR_THREADS,
51-
application_version=VERSION,
51+
application_version=VERSION, # octobot version
52+
executor_id=octobot_node.constants.SCHEDULER_EXECUTOR_ID,
5253
)
5354

5455

0 commit comments

Comments
 (0)