Skip to content

Commit adffc06

Browse files
committed
Some plain dev cleanup
1 parent 88f06c5 commit adffc06

File tree

4 files changed

+48
-85
lines changed

4 files changed

+48
-85
lines changed

plain-dev/plain/dev/cli.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def _auto_start_services():
4242
return
4343

4444
click.secho(
45-
"Starting dev services in the background (use `plain dev --stop` to kill)...",
45+
"Starting background dev services (terminate with `plain dev --stop`)...",
4646
dim=True,
4747
)
4848

@@ -53,6 +53,20 @@ def _auto_start_services():
5353
stderr=subprocess.DEVNULL,
5454
)
5555

56+
time.sleep(0.5) # Give it a moment to start
57+
58+
# If it's already dead, show the output and quit
59+
if not ServicesProcess.running_pid():
60+
click.secho(
61+
"Failed to start dev services. Here are the logs:",
62+
fg="red",
63+
)
64+
subprocess.run(
65+
["plain", "dev", "logs", "--services"],
66+
check=False,
67+
)
68+
sys.exit(1)
69+
5670

5771
@register_cli("dev")
5872
@click.group(cls=DevGroup, invoke_without_command=True)
@@ -104,6 +118,8 @@ def cli(ctx, port, hostname, log_level, start, stop):
104118
"You cannot use both --start and --stop at the same time."
105119
)
106120

121+
os.environ["PLAIN_DEV_SERVICES_AUTO"] = "false"
122+
107123
dev = DevProcess(
108124
port=port,
109125
hostname=hostname,

plain-dev/plain/dev/core.py

Lines changed: 29 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import json
2-
import multiprocessing
32
import os
43
import platform
5-
import signal
64
import socket
75
import subprocess
86
import sys
@@ -20,7 +18,6 @@
2018

2119
from .mkcert import MkcertManager
2220
from .process import ProcessManager
23-
from .services import ServicesProcess
2421
from .utils import has_pyproject_toml
2522

2623
ENTRYPOINT_GROUP = "plain.dev"
@@ -132,7 +129,6 @@ def _port_available(self, port):
132129

133130
def run(self):
134131
self.write_pidfile()
135-
click.secho(f"PID: {self.pid_value}", dim=True)
136132
mkcert_manager = MkcertManager()
137133
mkcert_manager.setup_mkcert(install_path=Path.home() / ".plain" / "dev")
138134
self.ssl_cert_path, self.ssl_key_path = mkcert_manager.generate_certs(
@@ -143,49 +139,39 @@ def run(self):
143139
self.symlink_plain_src()
144140
self.modify_hosts_file()
145141
self.set_allowed_hosts()
142+
143+
click.secho("→ Running preflight checks... ", dim=True, nl=False)
146144
self.run_preflight()
147145

148-
# If we start services ourselves, we should manage the pidfile
149-
services_proc = None
150-
151-
# Services start first (or are already running from a separate command)
152-
if running_pid := ServicesProcess().running_pid():
153-
click.secho(f"Services already running (pid={running_pid})", fg="yellow")
154-
elif services := ServicesProcess.get_services(APP_PATH.parent):
155-
click.secho("\nStarting services...", italic=True, dim=True)
156-
services_proc = ServicesProcess()
157-
services_proc.write_pidfile()
158-
159-
for name, data in services.items():
160-
env = {
161-
**os.environ,
162-
"PYTHONUNBUFFERED": "true",
163-
**data.get("env", {}),
164-
}
165-
self.poncho.add_process(name, data["cmd"], env=env)
166-
167-
# If plain.models is installed (common) then we
168-
# will do a couple extra things before starting all of the app-related
169-
# processes (this way they don't all have to db-wait or anything)
170-
process = None
171-
if find_spec("plain.models") is not None:
172-
# Use a custom signal to tell the main thread to add
173-
# the app processes once the db is ready
174-
signal.signal(signal.SIGUSR1, self.start_app)
175-
176-
process = multiprocessing.Process(
177-
target=_process_task, args=(self.plain_env,)
146+
# if ServicesProcess.running_pid():
147+
# self.poncho.add_process(
148+
# "services",
149+
# f"{sys.executable} -m plain dev logs --services --follow",
150+
# )
151+
152+
if find_spec("plain.models"):
153+
click.secho("→ Waiting for database... ", dim=True, nl=False)
154+
subprocess.run(
155+
[sys.executable, "-m", "plain", "models", "db-wait"],
156+
env=self.plain_env,
157+
check=True,
158+
)
159+
click.secho("→ Running migrations...", dim=True)
160+
subprocess.run(
161+
[sys.executable, "-m", "plain", "migrate", "--backup"],
162+
env=self.plain_env,
163+
check=True,
178164
)
179-
process.start()
180165

181-
# If there are no poncho processes, then let this process finish before
182-
# continuing (vs running in parallel)
183-
if self.poncho.num_processes() == 0:
184-
# Wait for the process to finish
185-
process.join()
186-
else:
187-
# Start the app processes immediately
188-
self.start_app(None, None)
166+
click.secho("\n→ Starting app...", dim=True)
167+
168+
# Manually start the status bar now so it isn't bungled by
169+
# another thread checking db stuff...
170+
self.console_status.start()
171+
172+
self.add_gunicorn()
173+
self.add_entrypoints()
174+
self.add_pyproject_run()
189175

190176
try:
191177
# Start processes we know about and block the main thread
@@ -195,35 +181,10 @@ def run(self):
195181
self.console_status.stop()
196182
finally:
197183
self.rm_pidfile()
198-
# Make sure the services pid gets removed if we set it
199-
if services_proc:
200-
services_proc.rm_pidfile()
201-
202184
self.close()
203185

204-
# Make sure the process is terminated if it is still running
205-
if process and process.is_alive():
206-
os.killpg(os.getpgid(process.pid), signal.SIGTERM)
207-
process.join(timeout=3)
208-
if process.is_alive():
209-
os.killpg(os.getpgid(process.pid), signal.SIGKILL)
210-
process.join()
211-
212186
return self.poncho.returncode
213187

214-
def start_app(self, signum, frame):
215-
# This runs in the main thread when SIGUSR1 is received
216-
# (or called directly if no thread).
217-
click.secho("\nStarting app...", italic=True, dim=True)
218-
219-
# Manually start the status bar now so it isn't bungled by
220-
# another thread checking db stuff...
221-
self.console_status.start()
222-
223-
self.add_gunicorn()
224-
self.add_entrypoints()
225-
self.add_pyproject_run()
226-
227188
def symlink_plain_src(self):
228189
"""Symlink the plain package into .plain so we can look at it easily"""
229190
plain_path = Path(find_spec("plain.runtime").origin).parent.parent
@@ -316,7 +277,6 @@ def set_allowed_hosts(self):
316277
)
317278

318279
def run_preflight(self):
319-
click.echo()
320280
if subprocess.run(["plain", "preflight"], env=self.plain_env).returncode:
321281
click.secho("Preflight check failed!", fg="red")
322282
sys.exit(1)
@@ -386,16 +346,3 @@ def add_pyproject_run(self):
386346
**data.get("env", {}),
387347
}
388348
self.poncho.add_process(name, data["cmd"], env=env)
389-
390-
391-
def _process_task(env):
392-
# Make this process the leader of a new group which can be killed together if it doesn't finish
393-
os.setsid()
394-
395-
subprocess.run(["plain", "models", "db-wait"], env=env, check=True)
396-
subprocess.run(["plain", "migrate", "--backup"], env=env, check=True)
397-
398-
# preflight with db?
399-
400-
# Send SIGUSR1 to the parent process so the parent's handler is invoked
401-
os.kill(os.getppid(), signal.SIGUSR1)

plain-models/plain/models/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def db_wait():
9292
)
9393
time.sleep(1.5)
9494
else:
95-
click.secho("Database ready", fg="green")
95+
click.secho("Database ready", fg="green")
9696
break
9797

9898

plain/plain/cli/preflight.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,4 @@ def preflight_checks(package_label, deploy, fail_level, database):
123123
msg = header + body + footer
124124
click.echo(msg, err=True)
125125
else:
126-
click.secho("✔ Preflight check identified no issues.", err=True, fg="green")
126+
click.secho("✔ Checks passed", err=True, fg="green")

0 commit comments

Comments
 (0)