Skip to content

Commit 6ffbcc4

Browse files
authored
Merge pull request #2903 from chaoss/dev
Release Ready
2 parents b778fcd + aae2f19 commit 6ffbcc4

File tree

21 files changed

+1432
-150
lines changed

21 files changed

+1432
-150
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ augur_export_env.sh
1010
config.yml
1111
reports.yml
1212
*.pid
13+
*.sock
1314

1415
node_modules/
1516
.idea/

augur/api/view/init.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,4 @@ def write_settings(current_settings):
9191
# Initialize logging
9292
def init_logging():
9393
global logger
94-
logger = AugurLogger("augur_view", reset_logfiles=True).get_logger()
94+
logger = AugurLogger("augur_view", reset_logfiles=False).get_logger()

augur/application/cli/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def new_func(ctx, *args, **kwargs):
3232
You are not connected to the internet.\n \
3333
Please connect to the internet to run Augur\n \
3434
Consider setting http_proxy variables for limited access installations.")
35-
sys.exit()
35+
sys.exit(-1)
3636

3737
return update_wrapper(new_func, function_internet_connection)
3838

@@ -78,7 +78,7 @@ def new_func(ctx, *args, **kwargs):
7878
print(f"\n\n{usage} command setup failed\nERROR: connecting to database\nHINT: The {incorrect_values} may be incorrectly specified in {location}\n")
7979

8080
engine.dispose()
81-
sys.exit()
81+
sys.exit(-2)
8282

8383
return update_wrapper(new_func, function_db_connection)
8484

augur/application/cli/_multicommand.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ def get_command(self, ctx, name):
3030

3131
# Check that the command exists before importing
3232
if not cmdfile.is_file():
33-
3433
return
3534

3635
# Prefer to raise exception instead of silcencing it

augur/application/cli/api.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414

1515
from augur.application.db.session import DatabaseSession
1616
from augur.application.logs import AugurLogger
17-
from augur.application.cli import test_connection, test_db_connection, with_database
17+
from augur.application.cli import test_connection, test_db_connection, with_database, DatabaseContext
1818
from augur.application.cli._cli_util import _broadcast_signal_to_processes, raise_open_file_limit, clear_redis_caches, clear_rabbitmq_messages
1919
from augur.application.db.lib import get_value
2020

21-
logger = AugurLogger("augur", reset_logfiles=True).get_logger()
21+
logger = AugurLogger("augur", reset_logfiles=False).get_logger()
2222

2323
@click.group('api', short_help='Commands for controlling the backend API server')
24-
def cli():
25-
pass
24+
@click.pass_context
25+
def cli(ctx):
26+
ctx.obj = DatabaseContext()
2627

2728
@cli.command("start")
2829
@click.option("--development", is_flag=True, default=False, help="Enable development mode")

augur/application/cli/backend.py

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ def cli(ctx):
4747
@click.pass_context
4848
def start(ctx, disable_collection, development, pidfile, port):
4949
"""Start Augur's backend server."""
50-
with open(pidfile, "w") as pidfile:
51-
pidfile.write(str(os.getpid()))
50+
with open(pidfile, "w") as pidfile_io:
51+
pidfile_io.write(str(os.getpid()))
5252

5353
try:
5454
if os.environ.get('AUGUR_DOCKER_DEPLOY') != "1":
@@ -63,6 +63,8 @@ def start(ctx, disable_collection, development, pidfile, port):
6363
if development:
6464
os.environ["AUGUR_DEV"] = "1"
6565
logger.info("Starting in development mode")
66+
67+
os.environ["AUGUR_PIDFILE"] = pidfile
6668

6769
try:
6870
gunicorn_location = os.getcwd() + "/augur/api/gunicorn_conf.py"
@@ -74,6 +76,11 @@ def start(ctx, disable_collection, development, pidfile, port):
7476
if not port:
7577
port = get_value("Server", "port")
7678

79+
os.environ["AUGUR_PORT"] = str(port)
80+
81+
if disable_collection:
82+
os.environ["AUGUR_DISABLE_COLLECTION"] = "1"
83+
7784
worker_vmem_cap = get_value("Celery", 'worker_process_vmem_cap')
7885

7986
gunicorn_command = f"gunicorn -c {gunicorn_location} -b {host}:{port} augur.api.server:app --log-file gunicorn.log"
@@ -128,7 +135,7 @@ def start(ctx, disable_collection, development, pidfile, port):
128135
augur_collection_monitor.si().apply_async()
129136

130137
else:
131-
logger.info("Collection disabled")
138+
logger.info("Collection disabled")
132139

133140
try:
134141
server.wait()
@@ -153,6 +160,8 @@ def start(ctx, disable_collection, development, pidfile, port):
153160
cleanup_after_collection_halt(logger, ctx.obj.engine)
154161
except RedisConnectionError:
155162
pass
163+
164+
os.unlink(pidfile)
156165

157166
def start_celery_worker_processes(vmem_cap_ratio, disable_collection=False):
158167

@@ -224,6 +233,54 @@ def stop(ctx):
224233

225234
augur_stop(signal.SIGTERM, logger, ctx.obj.engine)
226235

236+
@cli.command('stop-collection-blocking')
237+
@test_connection
238+
@test_db_connection
239+
@with_database
240+
@click.pass_context
241+
def stop_collection(ctx):
242+
"""
243+
Stop collection tasks if they are running, block until complete
244+
"""
245+
processes = get_augur_processes()
246+
247+
stopped = []
248+
249+
p: psutil.Process
250+
for p in processes:
251+
if p.name() == "celery":
252+
stopped.append(p)
253+
p.terminate()
254+
255+
if not len(stopped):
256+
logger.info("No collection processes found")
257+
return
258+
259+
_, alive = psutil.wait_procs(stopped, 5,
260+
lambda p: logger.info(f"STOPPED: {p.pid}"))
261+
262+
killed = []
263+
while True:
264+
for i in range(len(alive)):
265+
if alive[i].status() == psutil.STATUS_ZOMBIE:
266+
logger.info(f"KILLING ZOMBIE: {alive[i].pid}")
267+
alive[i].kill()
268+
killed.append(i)
269+
elif not alive[i].is_running():
270+
logger.info(f"STOPPED: {p.pid}")
271+
killed.append(i)
272+
273+
for i in reversed(killed):
274+
alive.pop(i)
275+
276+
if not len(alive):
277+
break
278+
279+
logger.info(f"Waiting on [{', '.join(str(p.pid for p in alive))}]")
280+
time.sleep(0.5)
281+
282+
cleanup_after_collection_halt(logger, ctx.obj.engine)
283+
227284
@cli.command('kill')
228285
@test_connection
229286
@test_db_connection
@@ -388,7 +445,7 @@ def processes():
388445
Outputs the name/PID of all Augur server & worker processes"""
389446
augur_processes = get_augur_processes()
390447
for process in augur_processes:
391-
logger.info(f"Found process {process.pid}")
448+
logger.info(f"Found process {process.pid} [{process.name()}] -> Parent: {process.parent().pid}")
392449

393450
def get_augur_processes():
394451
augur_processes = []

augur/application/cli/collection.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@
2222
from augur.application.db.session import DatabaseSession
2323
from augur.application.logs import AugurLogger
2424
from augur.application.db.lib import get_value
25-
from augur.application.cli import test_connection, test_db_connection, with_database
25+
from augur.application.cli import test_connection, test_db_connection, with_database, DatabaseContext
2626
from augur.application.cli._cli_util import _broadcast_signal_to_processes, raise_open_file_limit, clear_redis_caches, clear_rabbitmq_messages
2727

28-
logger = AugurLogger("augur", reset_logfiles=True).get_logger()
28+
logger = AugurLogger("augur", reset_logfiles=False).get_logger()
2929

3030
@click.group('server', short_help='Commands for controlling the backend API server & data collection workers')
31-
def cli():
32-
pass
31+
@click.pass_context
32+
def cli(ctx):
33+
ctx.obj = DatabaseContext()
3334

3435
@cli.command("start")
3536
@click.option("--development", is_flag=True, default=False, help="Enable development mode, implies --disable-collection")

augur/application/cli/jumpstart.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import psutil
2+
import click
3+
import time
4+
import subprocess
5+
from pathlib import Path
6+
from datetime import datetime
7+
8+
@click.group(invoke_without_command=True)
9+
@click.pass_context
10+
def cli(ctx):
11+
if ctx.invoked_subcommand is None:
12+
p = check_running()
13+
if not p:
14+
click.echo("Jumpstart is not running. Start it with: augur jumpstart run")
15+
return
16+
17+
click.echo(f"Connecting to Jumpstart: [{p.pid}]")
18+
19+
while p.is_running() and not len(p.connections("unix")):
20+
# Waiting for app to open fd socket
21+
time.sleep(0.1)
22+
23+
if not p.is_running():
24+
click.echo("Error: Jumpstart server exited abnormally")
25+
return
26+
27+
from jumpstart.tui import run_app
28+
run_app(ctx=ctx)
29+
30+
def check_running(pidfile = ".jumpstart.pid") -> psutil.Process:
31+
jumpidf = Path(pidfile)
32+
33+
try:
34+
jumpid, create_time = jumpidf.read_text().splitlines()
35+
jumpp = psutil.Process(int(jumpid))
36+
37+
if create_time != str(jumpp.create_time()):
38+
# PID was reused, not the original
39+
jumpidf.unlink()
40+
return
41+
42+
return jumpp
43+
except (psutil.NoSuchProcess, FileNotFoundError):
44+
return
45+
except PermissionError:
46+
click.echo(f"Permission denied while reading from or writing to pidfile [{str(jumpidf.resolve())}]")
47+
48+
@cli.command("status")
49+
def get_status():
50+
p = check_running()
51+
52+
if not p:
53+
click.echo("Jumpstart is not running")
54+
else:
55+
since = datetime.fromtimestamp(p.create_time()).astimezone()
56+
delta = datetime.now().astimezone() - since
57+
click.echo(f"Jumpstart is running at: [{p.pid}] since {since.strftime('%a %b %d, %Y %H:%M:%S %z:%Z')} [{delta}]")
58+
59+
@cli.command("run")
60+
@click.pass_context
61+
def startup(ctx):
62+
p = check_running()
63+
64+
if not p:
65+
click.echo("Starting")
66+
p = launch(ctx)
67+
else:
68+
click.echo(f"Jumpstart is already running [{p.pid}]")
69+
70+
@cli.command("processID")
71+
def get_main_ID():
72+
p = check_running()
73+
74+
if p:
75+
click.echo(p.pid)
76+
77+
@cli.command("shutdown")
78+
def shutdown_server():
79+
p = check_running()
80+
81+
if not p:
82+
click.echo("Jumpstart is not running")
83+
return
84+
85+
click.echo("Blocking on shutdown")
86+
p.terminate()
87+
p.wait()
88+
89+
def launch(ctx, pidfile = ".jumpstart.pid", socketfile = "jumpstart.sock"):
90+
service = subprocess.Popen(f"python -m jumpstart.jumpstart pidfile={pidfile} socketfile={socketfile}".split())
91+
92+
# Popen object does not have create_time for some reason
93+
ext_process = psutil.Process(service.pid)
94+
95+
with open(pidfile, "w") as file:
96+
file.write(f"{ext_process.pid}\n{ext_process.create_time()}")
97+
98+
return ext_process

augur/application/cli/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from augur.application.cli import test_connection, test_db_connection
1818
from augur.application.cli.backend import clear_rabbitmq_messages, raise_open_file_limit
1919

20-
logger = AugurLogger("augur", reset_logfiles=True).get_logger()
20+
logger = AugurLogger("augur", reset_logfiles=False).get_logger()
2121

2222
@click.group('celery', short_help='Commands for controlling the backend API server & data collection workers')
2323
def cli():

augur/application/db/data_parse.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,21 +283,21 @@ def extract_pr_review_message_ref_data(comment: dict, augur_pr_review_id, github
283283
return pr_review_comment_message_ref
284284

285285

286-
def extract_pr_event_data(event: dict, pr_id: int, platform_id: int, repo_id: int, tool_source: str, tool_version: str, data_source: str) -> dict:
286+
def extract_pr_event_data(event: dict, pr_id: int, gh_src_id: int, platform_id: int, repo_id: int, tool_source: str, tool_version: str, data_source: str) -> dict:
287287

288288
pr_event = {
289289
'pull_request_id': pr_id,
290290
'cntrb_id': event["cntrb_id"] if "cntrb_id" in event else None,
291291
'action': event['event'],
292292
'action_commit_hash': None,
293293
'created_at': event['created_at'],
294-
'issue_event_src_id': int(event['issue']["id"]),
294+
'issue_event_src_id': gh_src_id,
295295
'node_id': event['node_id'],
296296
'node_url': event['url'],
297297
'tool_source': tool_source,
298298
'tool_version': tool_version,
299299
'data_source': data_source,
300-
'pr_platform_event_id': int(event['issue']["id"]),
300+
'pr_platform_event_id': gh_src_id,
301301
'platform_id': platform_id,
302302
'repo_id': repo_id
303303
}

0 commit comments

Comments
 (0)