flowmesh-cli-stack 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {flowmesh_cli_stack-0.1.2/src/flowmesh_cli_stack.egg-info → flowmesh_cli_stack-0.1.3}/PKG-INFO +3 -3
  2. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/pyproject.toml +3 -3
  3. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/assets/.env.example +2 -0
  4. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/env_schema.py +12 -0
  5. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/stack.py +65 -11
  6. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/worker.py +23 -1
  7. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3/src/flowmesh_cli_stack.egg-info}/PKG-INFO +3 -3
  8. flowmesh_cli_stack-0.1.3/src/flowmesh_cli_stack.egg-info/requires.txt +5 -0
  9. flowmesh_cli_stack-0.1.2/src/flowmesh_cli_stack.egg-info/requires.txt +0 -5
  10. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/LICENSE +0 -0
  11. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/README.md +0 -0
  12. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/setup.cfg +0 -0
  13. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/__init__.py +0 -0
  14. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/assets/compose.yml +0 -0
  15. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/assets/docker-bake.hcl +0 -0
  16. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/bundle.py +0 -0
  17. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack/utils.py +0 -0
  18. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack.egg-info/SOURCES.txt +0 -0
  19. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack.egg-info/dependency_links.txt +0 -0
  20. {flowmesh_cli_stack-0.1.2 → flowmesh_cli_stack-0.1.3}/src/flowmesh_cli_stack.egg-info/top_level.txt +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flowmesh-cli-stack
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: FlowMesh CLI stack commands
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.12
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
- Requires-Dist: flowmesh-cli==0.1.2
10
- Requires-Dist: flowmesh-sdk-stack==0.1.2
9
+ Requires-Dist: flowmesh-cli==0.1.3
10
+ Requires-Dist: flowmesh-sdk-stack==0.1.3
11
11
  Requires-Dist: docker>=7.1.0
12
12
  Requires-Dist: packaging>=24
13
13
  Requires-Dist: pyyaml>=6.0.2
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "flowmesh-cli-stack"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "FlowMesh CLI stack commands"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
11
11
  license = "Apache-2.0"
12
12
  license-files = ["LICENSE"]
13
13
  dependencies = [
14
- "flowmesh-cli==0.1.2",
15
- "flowmesh-sdk-stack==0.1.2",
14
+ "flowmesh-cli==0.1.3",
15
+ "flowmesh-sdk-stack==0.1.3",
16
16
  "docker>=7.1.0",
17
17
  "packaging>=24",
18
18
  "pyyaml>=6.0.2",
@@ -117,9 +117,11 @@ TASK_MERGE_MAX_BATCH_SIZE=4
117
117
  ENABLE_CONTEXT_REUSE=true
118
118
  WORKER_CACHE_TTL_SEC=3600
119
119
  ENABLE_STAGE_WEIGHT_STICKINESS=false
120
+ TASK_NO_WORKER_GRACE_SEC=60
120
121
  ENABLE_WORKER_WATCHDOG=true
121
122
  WORKER_DEATH_CHECK_INTERVAL=30
122
123
  WORKER_DEATH_GRACE_SEC=60
124
+ WORKER_REHYDRATION_GRACE_SEC=120
123
125
 
124
126
  # ==== Server Heartbeat ====
125
127
  SERVER_HEARTBEAT_INTERVAL=30
@@ -388,6 +388,12 @@ STACK_ENV_SCHEMA = EnvSchema(
388
388
  "false",
389
389
  var_type=EnvVarType.BOOL,
390
390
  ),
391
+ EnvVar(
392
+ "TASK_NO_WORKER_GRACE_SEC",
393
+ "60",
394
+ var_type=EnvVarType.INT,
395
+ min_value=0,
396
+ ),
391
397
  EnvVar("ENABLE_WORKER_WATCHDOG", "true", var_type=EnvVarType.BOOL),
392
398
  EnvVar(
393
399
  "WORKER_DEATH_CHECK_INTERVAL",
@@ -401,6 +407,12 @@ STACK_ENV_SCHEMA = EnvSchema(
401
407
  var_type=EnvVarType.INT,
402
408
  min_value=0,
403
409
  ),
410
+ EnvVar(
411
+ "WORKER_REHYDRATION_GRACE_SEC",
412
+ "120",
413
+ var_type=EnvVarType.INT,
414
+ min_value=0,
415
+ ),
404
416
  ],
405
417
  ),
406
418
  EnvSection(
@@ -531,33 +531,87 @@ def down(
531
531
  logging.success("FlowMesh stack stopped.")
532
532
 
533
533
 
534
+ STACK_SERVICES = ("server", "redis_control", "redis_telemetry")
535
+ """Compose services that can be restarted individually."""
536
+
537
+ WORKER_MANAGING_SERVICES = ("server",)
538
+ """Services whose restart tears down the supervisor; drain workers first."""
539
+
540
+
534
541
  @app.command()
535
542
  def restart(
543
+ services: list[str] | None = typer.Argument(
544
+ None,
545
+ help=(
546
+ "Restart only these compose services in place (any of: "
547
+ f"{', '.join(STACK_SERVICES)}), leaving the rest of the stack "
548
+ "running. Omit to restart the whole stack."
549
+ ),
550
+ ),
536
551
  env_file: Path = typer.Option(
537
552
  DEFAULT_ENV_FILE, "--env-file", help="Env file for compose"
538
553
  ),
539
554
  image_tag: str | None = typer.Option(
540
555
  None, "--image-tag", help="Override FLOWMESH_VERSION"
541
556
  ),
557
+ pull: bool = typer.Option(
558
+ True, "--pull/--no-pull", help="Pull the target image before recreating."
559
+ ),
542
560
  ) -> None:
543
- """Drain workers and restart the stack."""
544
- logging.info("Draining workers...")
545
- _drain_workers(env_file)
546
- _compose(
547
- ["down"],
548
- env_file=env_file,
549
- env=image_env_overrides(image_tag),
550
- profile="root",
551
- )
561
+ """Drain workers and restart the stack, or recreate specific services in place.
562
+
563
+ With one or more SERVICE arguments the stack is left running and only those services
564
+ are recreated; when any of them manages workers (the server / supervisor) its
565
+ workers are drained first so their in-flight tasks requeue onto other nodes.
566
+ """
567
+ if not services:
568
+ logging.info("Draining workers...")
569
+ _drain_workers(env_file)
570
+ _compose(
571
+ ["down"],
572
+ env_file=env_file,
573
+ env=image_env_overrides(image_tag),
574
+ profile="root",
575
+ )
576
+ profile = "root" if _node_role(env_file) == NodeRole.ROOT else None
577
+ _compose(
578
+ ["up", "-d", "--wait"],
579
+ env_file=env_file,
580
+ env=image_env_overrides(image_tag),
581
+ to_deploy=True,
582
+ profile=profile,
583
+ )
584
+ logging.success("FlowMesh stack is up.")
585
+ return
586
+
587
+ requested = list(dict.fromkeys(services))
588
+ unknown = [svc for svc in requested if svc not in STACK_SERVICES]
589
+ if unknown:
590
+ logging.error(
591
+ f"Unknown service(s): {', '.join(unknown)}. "
592
+ f"Known services: {', '.join(STACK_SERVICES)}."
593
+ )
594
+ raise typer.Exit(code=1)
595
+
596
+ if any(svc in WORKER_MANAGING_SERVICES for svc in requested):
597
+ logging.info("Draining workers...")
598
+ _drain_workers(env_file)
599
+
552
600
  profile = "root" if _node_role(env_file) == NodeRole.ROOT else None
601
+ up_args = ["up", "-d", "--no-deps", "--force-recreate", "--wait"]
602
+ if pull:
603
+ up_args += ["--pull", "always"]
604
+ up_args += requested
605
+ joined = ", ".join(requested)
606
+ logging.info(f"Recreating service(s): {joined}...")
553
607
  _compose(
554
- ["up", "-d", "--wait"],
608
+ up_args,
555
609
  env_file=env_file,
556
610
  env=image_env_overrides(image_tag),
557
611
  to_deploy=True,
558
612
  profile=profile,
559
613
  )
560
- logging.success("FlowMesh stack is up.")
614
+ logging.success(f"Service(s) restarted: {joined}.")
561
615
 
562
616
 
563
617
  @app.command()
@@ -18,7 +18,13 @@ from flowmesh_stack.workers import (
18
18
  select_worker_images,
19
19
  )
20
20
 
21
- from .utils import DEFAULT_ENV_FILE, STACK_PATH_KEYS, stack_node_client
21
+ from .utils import (
22
+ DEFAULT_ENV_FILE,
23
+ STACK_PATH_KEYS,
24
+ STACK_SLUG_ENV,
25
+ stack_node_client,
26
+ stack_resource_env_overrides,
27
+ )
22
28
 
23
29
  app = get_typer(help="Create and manage workers on the local node.")
24
30
 
@@ -74,6 +80,15 @@ def worker_up(
74
80
  "Repeat --config-raw to provide multiple configs."
75
81
  ),
76
82
  ),
83
+ name_template: str | None = typer.Option(
84
+ None,
85
+ "--name-template",
86
+ help=(
87
+ "Worker name template for cpu/gpu presets. Placeholders: "
88
+ "{slug}, {kind}, {idx}, {gpu}. "
89
+ "Default: '{slug}_worker_{kind}_{idx|gpu}'."
90
+ ),
91
+ ),
77
92
  env_file: Path = typer.Option(
78
93
  DEFAULT_ENV_FILE, "--env-file", help="Env file to load defaults"
79
94
  ),
@@ -84,6 +99,11 @@ def worker_up(
84
99
  ) -> None:
85
100
  """Create and start one or more workers from presets or a custom config file."""
86
101
  client = stack_node_client(env_file, base_url, token or None)
102
+ try:
103
+ slug = stack_resource_env_overrides(os.environ)[STACK_SLUG_ENV]
104
+ except ValueError as exc:
105
+ logging.error(str(exc))
106
+ raise typer.Exit(code=1)
87
107
  logging.info("Creating workers...")
88
108
  try:
89
109
  created = create_workers(
@@ -93,6 +113,8 @@ def worker_up(
93
113
  targets=targets,
94
114
  config_paths=config,
95
115
  config_raw=config_raw,
116
+ name_template=name_template,
117
+ slug=slug,
96
118
  )
97
119
  except FlowMeshError as exc:
98
120
  logging.error(str(exc))
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flowmesh-cli-stack
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: FlowMesh CLI stack commands
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.12
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
- Requires-Dist: flowmesh-cli==0.1.2
10
- Requires-Dist: flowmesh-sdk-stack==0.1.2
9
+ Requires-Dist: flowmesh-cli==0.1.3
10
+ Requires-Dist: flowmesh-sdk-stack==0.1.3
11
11
  Requires-Dist: docker>=7.1.0
12
12
  Requires-Dist: packaging>=24
13
13
  Requires-Dist: pyyaml>=6.0.2
@@ -0,0 +1,5 @@
1
+ flowmesh-cli==0.1.3
2
+ flowmesh-sdk-stack==0.1.3
3
+ docker>=7.1.0
4
+ packaging>=24
5
+ pyyaml>=6.0.2
@@ -1,5 +0,0 @@
1
- flowmesh-cli==0.1.2
2
- flowmesh-sdk-stack==0.1.2
3
- docker>=7.1.0
4
- packaging>=24
5
- pyyaml>=6.0.2