@@ -71,7 +71,9 @@ def _list_instances_impl(
7171 else :
7272 # Worker/scheduler: query by notes containing instance ID
7373 deployments = db .get_deployments (
74- cfg .db_path , limit = 1 , notes_like = f"%{ inst_type .value } _id={ id_ } %"
74+ cfg .db_path ,
75+ limit = 1 ,
76+ notes_like = f"%{ inst_type .value } _id={ id_ } %" ,
7577 )
7678 if deployments :
7779 dep = deployments [0 ]
@@ -132,7 +134,9 @@ def _list_instances_impl(
132134 else :
133135 # Worker/scheduler: query by notes containing instance ID
134136 deployments = db .get_deployments (
135- cfg .db_path , limit = 1 , notes_like = f"%{ inst_type .value } _id={ id_ } %"
137+ cfg .db_path ,
138+ limit = 1 ,
139+ notes_like = f"%{ inst_type .value } _id={ id_ } %" ,
136140 )
137141 if deployments :
138142 dep = deployments [0 ]
@@ -737,17 +741,20 @@ def restart(
737741 web : WebFlag = False ,
738742 worker : WorkerFlag = False ,
739743 scheduler : SchedulerFlag = False ,
744+ delay : Delay = 30 ,
740745):
741746 """Restart systemd unit(s) for instance(s).
742747
743748 Does NOT regenerate quadlet - use 'redeploy' for that.
744749 Only restarts running instances; stopped instances are skipped.
750+ Waits between instances to allow startup before Caddy health checks.
745751
746752 Examples:
747753 ots instances restart # Restart all running
748754 ots instances restart --web # Restart web instances
749755 ots instances restart --web 7043 7044 # Restart specific web
750756 ots instances restart --scheduler main # Restart specific scheduler
757+ ots instances restart --delay 10 # Longer wait between restarts
751758 """
752759 itype = resolve_instance_type (instance_type , web , worker , scheduler )
753760 instances = resolve_identifiers (identifiers , itype , running_only = True )
@@ -756,15 +763,11 @@ def restart(
756763 print ("No running instances found" )
757764 return
758765
759- for inst_type , ids in instances .items ():
760- for id_ in ids :
761- unit = systemd .unit_name (inst_type .value , id_ )
762- systemd .restart (unit )
763- print (f"Restarted { unit } " )
766+ def do_restart (inst_type : InstanceType , id_ : str ) -> None :
767+ unit = systemd .unit_name (inst_type .value , id_ )
768+ systemd .restart (unit )
764769
765- hint = format_journalctl_hint (instances )
766- if hint :
767- print (f"\n View logs: { hint } " )
770+ for_each_instance (instances , delay , do_restart , "Restarting" , show_logs_hint = True )
768771
769772
770773@app .command
@@ -1019,6 +1022,20 @@ def shell(
10191022 help = "Named volume for persistent data (survives exit)" ,
10201023 ),
10211024 ] = None ,
1025+ volume : Annotated [
1026+ str | None ,
1027+ cyclopts .Parameter (
1028+ name = ["--volume" , "-v" ],
1029+ help = "Host path to bind-mount at /app/data (rw, user-mapped)" ,
1030+ ),
1031+ ] = None ,
1032+ env : Annotated [
1033+ tuple [str , ...],
1034+ cyclopts .Parameter (
1035+ name = ["--env" , "-e" ],
1036+ help = "Set container env var (KEY=VALUE, repeatable)" ,
1037+ ),
1038+ ] = (),
10221039 command : Annotated [
10231040 str | None ,
10241041 cyclopts .Parameter (
@@ -1046,14 +1063,24 @@ def shell(
10461063
10471064 By default uses tmpfs at /app/data (data destroyed on exit).
10481065 Use --persistent to create a named volume that survives exit.
1066+ Use --volume to bind-mount a host directory at /app/data.
10491067 Config is mounted read-only at /app/etc.
10501068
10511069 Examples:
10521070 ots instance shell # tmpfs, interactive bash
10531071 ots instance shell --persistent upgrade-v024 # named volume survives exit
10541072 ots instance shell -c "bin/ots migrate" # run command and exit
10551073 ots instance shell --tag v0.24.0 # specific image tag
1074+ ots instance shell -v ./data # bind-mount ./data at /app/data
1075+ ots instance shell -v ./data -e REDIS_URL=redis://10.0.0.5:6379/0 # with env
1076+ ots instance shell -e FOO=bar -e BAZ=qux # multiple env vars, tmpfs default
10561077 """
1078+ from pathlib import Path
1079+
1080+ if persistent and volume :
1081+ print ("Error: --persistent and --volume are mutually exclusive" )
1082+ raise SystemExit (1 )
1083+
10571084 cfg = Config ()
10581085
10591086 # Resolve image/tag (same pattern as run command)
@@ -1084,13 +1111,21 @@ def shell(
10841111 cmd .extend (["--env-file" , str (env_file )])
10851112 cmd .extend (build_secret_args (env_file ))
10861113
1087- # Data volume: tmpfs (default) or persistent named volume
1088- if persistent :
1114+ # Data volume: bind-mount, persistent named volume, or tmpfs (default)
1115+ if volume :
1116+ host_path = Path (volume ).resolve ()
1117+ host_path .mkdir (parents = True , exist_ok = True )
1118+ cmd .extend (["-v" , f"{ host_path } :/app/data:rw,U" ])
1119+ elif persistent :
10891120 volume_name = f"ots-migration-{ persistent } "
10901121 cmd .extend (["-v" , f"{ volume_name } :/app/data" ])
10911122 else :
10921123 cmd .extend (["--tmpfs" , "/app/data" ])
10931124
1125+ # Ad-hoc environment variables
1126+ for entry in env :
1127+ cmd .extend (["-e" , entry ])
1128+
10941129 # Config overrides (per-file, if any exist on host)
10951130 for f in cfg .existing_config_files :
10961131 resolved = f .resolve () # symlink resolution for macOS podman VM
0 commit comments