Bug 1622336 - Trigger schedules API as soon as a push happens (#1548)

This change adds a Pulse listener for hg pushes as a background process
to `bugbug-http-service`.

This listener works if `PULSE_USER` and `PULSE_PASSWORD` are set before starting
up the Docker containers.

The listener only pays attention to autoland and try pushes. When these happen
we do a GET request from the bugbug deployment. This will get the schedules service
ready for when the Gecko decision task will query it.
This commit is contained in:
Armen Zambrano 2020-05-08 11:05:16 -04:00 коммит произвёл GitHub
Родитель 893f1c3368
Коммит 2c4ee86e65
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 109 добавлений и 3 удалений

Просмотреть файл

@ -3,4 +3,4 @@ multi_line_output=3
include_trailing_comma=True
line_length=88
known_first_party = bugbug,bugbug_http
known_third_party = adr,apispec,apispec_webframeworks,boto3,cerberus,dateutil,flask,flask_cors,hglib,imblearn,joblib,jsone,jsonschema,libmozdata,lmdb,marshmallow,matplotlib,microannotate,mozci,numpy,orjson,pandas,pkg_resources,pyemd,pytest,redis,requests,responses,rq,scipy,setuptools,shap,sklearn,tabulate,taskcluster,tenacity,tqdm,xgboost,yaml,zstandard
known_third_party = adr,apispec,apispec_webframeworks,boto3,cerberus,dateutil,flask,flask_cors,hglib,imblearn,joblib,jsone,jsonschema,kombu,libmozdata,lmdb,marshmallow,matplotlib,microannotate,mozci,numpy,orjson,pandas,pkg_resources,pyemd,pytest,redis,requests,responses,rq,scipy,setuptools,shap,sklearn,tabulate,taskcluster,tenacity,tqdm,xgboost,yaml,zstandard

Просмотреть файл

@ -10,4 +10,5 @@ RUN pip install --disable-pip-version-check --quiet --no-cache-dir -r /requireme
COPY . /code/http_service
RUN pip install --disable-pip-version-check --quiet --no-cache-dir /code/http_service
CMD gunicorn -b 0.0.0.0:$PORT bugbug_http.app --preload --timeout 30 -w 3
# Run the Pulse listener in the background
CMD (bugbug-http-pulse-listener &) && gunicorn -b 0.0.0.0:$PORT bugbug_http.app --preload --timeout 30 -w 3

Просмотреть файл

@ -0,0 +1,96 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Generate your credentials in https://pulseguardian.mozilla.org
Call this script like:
export PULSE_USER=generated_username
export PULSE_PASSWORD=generated_username
# In case you want to hit the live server
export BUGBUG_HTTP_SERVER=https://bugbug.herokuapp.com
cd http_service && docker-compose run bugbug-http-service
"""
import logging
import os
import traceback
import requests
from kombu import Connection, Exchange, Queue
from kombu.mixins import ConsumerMixin
logging.basicConfig()
logger = logging.getLogger()
logger.setLevel(logging.INFO)
BUGBUG_HTTP_SERVER = os.environ.get("BUGBUG_HTTP_SERVER", "http://localhost:8000")
CONNECTION_URL = "amqp://{}:{}@pulse.mozilla.org:5671/?ssl=1"
class _GenericConsumer(ConsumerMixin):
def __init__(self, connection, queues, callback):
self.connection = connection
self.queues = queues
self.callback = callback
def get_consumers(self, Consumer, channel):
return [Consumer(queues=self.queues, callbacks=[self.callback])]
class HgPushesConsumer:
def __init__(self, user, password, callback):
self.connection = Connection(CONNECTION_URL.format(user, password))
self.queues = [
Queue(
name="queue/{}/pushes".format(user),
exchange=Exchange(
"exchange/hgpushes/v2", type="topic", no_declare=True,
),
routing_key="#",
durable=True,
auto_delete=True,
)
]
self.consumer = _GenericConsumer(self.connection, self.queues, callback)
def __enter__(self):
return self.consumer
def __exit__(self, type, value, traceback):
self.connection.close()
def _on_message(body, message):
try:
branch = body["payload"]["data"]["repo_url"].split("/")[-1]
rev = body["payload"]["data"]["heads"][0]
if branch in ["autoland", "try"]:
url = "{}/push/{}/{}/schedules".format(BUGBUG_HTTP_SERVER, branch, rev)
response = requests.get(url, headers={"X-Api-Key": "pulse_listener"})
if response.status_code == 202:
logger.info("Successfully requested {}/{}".format(branch, rev))
else:
logger.warning(
"We got status: {} for: {}".format(response.status_code, url)
)
except Exception as e:
traceback.print_tb(e)
finally:
message.ack()
def main():
# Generate user/password in https://pulseguardian.mozilla.org/
# Set PULSE_USER and PULSE_PASSWORD as env variables
user = os.environ.get("PULSE_USER")
password = os.environ.get("PULSE_PASSWORD")
if user and password:
with HgPushesConsumer(user, password, _on_message) as consumer:
consumer.run()
else:
logger.warning(
"The Pulse listener will be skipped unless you define PULSE_USER & PULSE_PASSWORD"
)
if __name__ == "__main__":
main()

Просмотреть файл

@ -8,6 +8,8 @@ services:
- BUGBUG_BUGZILLA_TOKEN
- REDIS_URL=redis://redis:6379/0
- PORT=8000
- PULSE_USER
- PULSE_PASSWORD
ports:
- target: 8000
published: 8000

Просмотреть файл

@ -5,6 +5,8 @@ Flask==1.1.2
flask-apispec==0.8.8
flask-cors==3.0.8
gunicorn==20.0.4
kombu==4.6.8
marshmallow==3.5.2
requests==2.23.0
rq==1.3.0
rq-dashboard==0.6.1

Просмотреть файл

@ -31,7 +31,12 @@ setup(
packages=find_packages(),
include_package_data=True,
license="MPL2",
entry_points={"console_scripts": ["bugbug-http-worker = bugbug_http.worker:main"]},
entry_points={
"console_scripts": [
"bugbug-http-worker = bugbug_http.worker:main",
"bugbug-http-pulse-listener = bugbug_http.listener:main",
]
},
classifiers=[
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3 :: Only",