Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add task queue #3

Merged
merged 17 commits into from
Aug 5, 2024
51 changes: 12 additions & 39 deletions .github/workflows/build-deploy-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,62 +12,35 @@ env:
GITLAB_REGISTRY_TOKEN: ${{ secrets.GITLAB_REGISTRY_TOKEN }}

jobs:
build-gateway:
runs-on: ubuntu-20.04
steps:
- name: Check out repo.
uses: actions/checkout@v4
- name: Setup buildx
run: docker buildx create --use
- name: Sign in to segmentation gitlab registry.
run: echo "$GITLAB_REGISTRY_TOKEN" | docker login registry.gitlab.com -u "$GITLAB_REGISTRY_USERNAME" --password-stdin
- name: Build gateway image.
run: |
docker buildx build \
--platform linux/arm64 \
--tag registry.gitlab.com/segmentation964330/service/gateway \
--push \
./gateway
build-nginx:
runs-on: ubuntu-20.04
steps:
- name: Check out repo.
uses: actions/checkout@v4
- name: Setup buildx
run: docker buildx create --use
- name: Sign in to segmentation gitlab registry.
run: echo "$GITLAB_REGISTRY_TOKEN" | docker login registry.gitlab.com -u "$GITLAB_REGISTRY_USERNAME" --password-stdin
- name: Build nginx image.
run: |
docker buildx build \
--platform linux/arm64 \
--tag registry.gitlab.com/segmentation964330/service/nginx \
--push \
./nginx
deploy:
runs-on: ubuntu-20.04
needs: [build-gateway, build-nginx]
steps:
- name: Check out repo.
uses: actions/checkout@v4
- name: Copy docker compose file to OCI.
- name: Copy directory to OCI.
uses: appleboy/[email protected]
with:
host: ${{ secrets.ORACLE_HOST }}
username: ${{ secrets.ORACLE_USERNAME }}
key: ${{ secrets.ORACLE_SSH_KEY }}
source: "./docker-compose.yml"
target: "."
source: "./"
target: "./SegmentationService"
- name: Pull docker and deploy.
uses: appleboy/[email protected]
with:
host: ${{ secrets.ORACLE_HOST }}
username: ${{ secrets.ORACLE_USERNAME }}
key: ${{ secrets.ORACLE_SSH_KEY }}
script_stop: true
envs: GITLAB_REGISTRY_USERNAME, GITLAB_REGISTRY_TOKEN
script: |
echo "$GITLAB_REGISTRY_TOKEN" | docker login registry.gitlab.com -u "$GITLAB_REGISTRY_USERNAME" --password-stdin
sudo docker compose down
sudo docker compose pull
cd SegmentationService
sudo docker compose build
sudo docker compose push
sudo docker stop $(sudo docker ps -a -q)
sudo docker rm $(sudo docker ps -a -q)
sudo docker compose up --detach
sudo docker image prune --force
sudo docker system prune --force
cd ..
rm -rf SegmentationService
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
*.DS_Store
artifacts
26 changes: 23 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
services:
redis:
container_name: redis
image: redis:7.0.15-alpine3.20
command: redis-server --bind redis --port 6379
tty: true
stdin_open: true
inference:
container_name: inference
image: registry.gitlab.com/segmentation964330/service/inference
build:
context: ./inference
volumes:
- ../artifacts/images:/home/artifacts/images
- ../artifacts/logs:/home/artifacts/logs
- ../artifacts/models:/home/artifacts/models
depends_on:
- redis
tty: true
stdin_open: true
gateway:
container_name: gateway
image: registry.gitlab.com/segmentation964330/service/gateway
build:
context: ./gateway
volumes:
- ./artifacts/images:/home/artifacts/images
- ./artifacts/logs:/home/artifacts/logs
- ./artifacts/models:/home/artifacts/models
- ../artifacts/images:/home/artifacts/images
- ../artifacts/logs:/home/artifacts/logs
depends_on:
- redis
tty: true
stdin_open: true
nginx:
Expand Down
Empty file removed gateway/.dockerignore
Empty file.
8 changes: 3 additions & 5 deletions gateway/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
FROM registry.gitlab.com/segmentation964330/service/torchbase
FROM python:3.12.4-alpine3.19

WORKDIR /home

COPY ./requirements.txt ./
RUN pip install -r requirements.txt
Expand All @@ -8,9 +10,5 @@ COPY . .
ENV WORKING_DIR="/home"
ENV LOGS_DIR="/home/artifacts/logs/"
ENV IMAGES_DIR="/home/artifacts/images/"
ENV MODELS_DIR="/home/artifacts/models/"
ENV SEGMENTATION_MODEL_NAME="pointrend_weights.pth"
ENV CLASSIFICATION_MODEL_NAME="swinv2_weights.pth"
ENV SPECIES_LIST="species.json"

CMD ["gunicorn", "-c", "gunicorn_conf.py", "app:gunicorn_app"]
2 changes: 1 addition & 1 deletion gateway/gunicorn_conf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

bind = '0.0.0.0:8000'
bind = 'gateway:8000'
accesslog = os.path.join(os.environ["LOGS_DIR"], 'gunicorn.log')
errorlog = os.path.join(os.environ["LOGS_DIR"], 'gunicorn.log')
workers = 1
4 changes: 3 additions & 1 deletion gateway/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ flask==3.0.3
numpy==1.26.4
pillow==10.4.0
gunicorn==22.0.0
flask-cors==4.0.1
flask-cors==4.0.1
redis==5.0.8
rq==1.16.2
69 changes: 30 additions & 39 deletions gateway/server/app.py
Original file line number Diff line number Diff line change
@@ -1,63 +1,54 @@
import server.init
server.init.init()

from flask import Flask, request, jsonify, render_template
from flask import Flask, request, jsonify
from flask_cors import CORS
from PIL import Image
from PIL import Image, ImageOps
import numpy as np
import uuid
import os
import logging

import server.classification as classification
import server.segmentation as segmentation

logger = logging.getLogger(__name__)
from server.taskqueue import TaskQueue

app = Flask(__name__)
CORS(app)

@app.route("/secretgui")
def gui():
return render_template("hi.html")
job_queue = TaskQueue("redis", "6379", "segmentation_queue")
logger = logging.getLogger(__name__)

@app.route("/healthcheck")
def hello_world():
logger.info("Healthcheck.")
return "Hello world!", 200
logger.info("Healthcheck run.")
return "Hello world.", 200

@app.route("/predict", methods=["POST"])
@app.route("/upload", methods=["POST"])
def predict():
if 'file' not in request.files:
logger.info("Predict with no image.")
logger.info("Uploaded with no file.")
return jsonify({'error': 'No file part in the request'}), 400
file = request.files['file']
try:
ip = request.environ['REMOTE_ADDR']
logger.info(f"Received image for {ip}.")
image = Image.open(file.stream)
# Need to remove alpha channel.
if image.mode in ("RGBA", "P"):
image = image.convert("RGB")
try:
imgid = str(uuid.uuid1())
image.save(os.path.join(os.environ['IMAGES_DIR'], imgid + ".jpg"))
logger.info(f"Saved img as {imgid} - {ip}.")
except Exception as e:
logger.warn(f"Failed to save img: {imgid} - {str(e)} - {ip}")
print(e)
npimg = np.array(image)

logger.info(f"Starting segmentation for {imgid}.")
subimgs, base64s = segmentation.predict(npimg, 0.95)
logger.info(f"Finished segmentation: predicted {len(base64s)} pitchers for {imgid}.")

logger.info(f"Starting classification for {imgid}.")
for i, img in enumerate(subimgs):
base64s[i]['classification_preds'] = classification.predict(img)
logger.info(f"Predicted: {base64s[i]['classification_preds']} for {imgid}.")
logger.info(f"Finished classification for {imgid}.")

return jsonify(base64s), 200
image = image.convert("RGB")
image = ImageOps.exif_transpose(image)

img_and_job_id = str(uuid.uuid4())
imgname = img_and_job_id + '.jpg'
image.save(os.path.join(os.environ['IMAGES_DIR'], imgname))
logger.info(f"Saved image: {imgname}.")
job_id = job_queue.add_task("inference.infer", imgname, img_and_job_id)
return job_id, 200
except Exception as e:
logger.error(f"Error in parsing and submitting image: {e}.")
return jsonify({'error': str(e)}), 400

@app.route("/status/<job_id>")
def status(job_id):
try:
job_status, code = job_queue.get_job_status(job_id)
except Exception as e:
logger.warn(f"Unable to find job {job_id}: {str(e)}.")
return jsonify({'error': str(e)}), 404
if job_status['done']:
logger.info(f"Job {job_id} queried with finished status.")
return jsonify(job_status), code
78 changes: 0 additions & 78 deletions gateway/server/classification.py

This file was deleted.

Loading