From ea5dcc622a2add1d19ba4b3b5b0e37bd724b9a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Agneray?= <francois.agneray@lam.fr> Date: Thu, 29 Sep 2022 16:51:05 +0200 Subject: [PATCH] For production run services with gunicorn --- services/Dockerfile | 2 +- services/src/anis_services/app.py | 331 +++++++++++++++--------------- 2 files changed, 169 insertions(+), 164 deletions(-) diff --git a/services/Dockerfile b/services/Dockerfile index 44ecce1e..64c6b6d2 100755 --- a/services/Dockerfile +++ b/services/Dockerfile @@ -6,4 +6,4 @@ COPY requirements.txt ./ COPY src src RUN pip install --no-cache-dir -r requirements.txt -CMD ["python3.8", "src/anis_services/app.py"] +CMD ["gunicorn", "-w", "8", "--timeout", "600", "-b", "0.0.0.0:80", "anis_services.app:create_app()"] diff --git a/services/src/anis_services/app.py b/services/src/anis_services/app.py index 742b8598..bb514aba 100644 --- a/services/src/anis_services/app.py +++ b/services/src/anis_services/app.py @@ -12,172 +12,177 @@ import plot import spectra import utils -app = Flask(__name__) -CORS(app) - -@app.route('/') -def index(): - return { - "message": "it works!" - } - -@app.route('/get-fits-image-limits/<dname>') -def get_fits_image_limits(dname): - filename = request.args.get('filename', default=None) - if filename is None: - return {"message": "Parameter filename is mandatory"}, 400 - - try: - file_path = utils.get_file_path(dname, filename) - except utils.DatasetNotFound as e: - return {"message": str(e)}, 404 - except utils.FileForbidden as e: - return {"message": str(e)}, 403 - except utils.FileNotFound as e: - return {"message": str(e)}, 404 - except utils.AnisServerError as e: - return {"message": str(e)}, 500 - - return cut.getImageLimits(file_path) - -@app.route('/fits-cut/<dname>') -def fits_cut(dname): - filename = request.args.get('filename', default=None) - if filename is None: - return {"message": "Parameter filename is mandatory"}, 400 - - ra = float(request.args.get('ra', '')) - dec = float(request.args.get('dec', '')) - radius = float(request.args.get('radius', '')) - - if ra is None: - return {"message": "Parameter ra is mandatory"}, 400 - if dec is None: - return {"message": "Parameter dec is mandatory"}, 400 - if radius is None: - return {"message": "Parameter radius is mandatory"}, 400 - - try: - file_path = utils.get_file_path(dname, filename) - except utils.DatasetNotFound as e: - return {"message": str(e)}, 404 - except utils.FileForbidden as e: - return {"message": str(e)}, 403 - except utils.FileNotFound as e: - return {"message": str(e)}, 404 - except utils.AnisServerError as e: - return {"message": str(e)}, 500 - - fits_file = cut.fits_cut(file_path, ra, dec, radius) - - output = io.BytesIO() - fits_file.writeto(output, overwrite=True) - return Response(output.getvalue(), mimetype='image/fits') - -@app.route('/fits-cut-to-png/<dname>') -def fits_cut_to_png(dname): - filename = request.args.get('filename', default=None) - if filename is None: - return {"message": "Parameter filename is mandatory"}, 400 - - ra = request.args.get('ra', default=None, type=float) - dec = request.args.get('dec', default=None, type=float) - radius = request.args.get('radius', default=None, type=float) - stretch = request.args.get('stretch', default=None) - pmin = request.args.get('pmin', default=None, type=float) - pmax = request.args.get('pmax', default=None, type=float) - axes = request.args.get('axes', default=None) - theme = request.args.get('theme', default=None) - - if ra is None: - return {"message": "Parameter ra is mandatory"}, 400 - if dec is None: - return {"message": "Parameter dec is mandatory"}, 400 - if radius is None: - return {"message": "Parameter radius is mandatory"}, 400 - if stretch is None: - return {"message": "Parameter stretch is mandatory"}, 400 - if pmin is None: - return {"message": "Parameter pmin is mandatory"}, 400 - if pmax is None: - return {"message": "Parameter pmax is mandatory"}, 400 - if axes is None: - return {"message": "Parameter axes is mandatory"}, 400 - - try: - file_path = utils.get_file_path(dname, filename) - except utils.DatasetNotFound as e: - return {"message": str(e)}, 404 - except utils.FileForbidden as e: - return {"message": str(e)}, 403 - except utils.FileNotFound as e: - return {"message": str(e)}, 404 - except utils.AnisServerError as e: - return {"message": str(e)}, 500 - - fits_file = cut.fits_cut(file_path, ra, dec, radius) - - output = io.BytesIO() - fig = plot.create_figure(fits_file, stretch, pmin, pmax, axes, theme) - if axes == 'true': - fig.savefig(output, format="png") - else: - fig.savefig(output, format="png", bbox_inches='tight', pad_inches = 0) - - return Response(output.getvalue(), mimetype='image/png') - -@app.route('/fits-to-png/<dname>') -def fits_to_png(dname): - filename = request.args.get('filename', default=None) - if filename is None: - return {"message": "Parameter filename is mandatory"}, 400 - - stretch = request.args.get('stretch', default=None) - pmin = request.args.get('pmin', default=None, type=float) - pmax = request.args.get('pmax', default=None, type=float) - axes = request.args.get('axes', default=None) - theme = request.args.get('theme', default=None) - - try: - file_path = utils.get_file_path(dname, filename) - except utils.DatasetNotFound as e: - return {"message": str(e)}, 404 - except utils.FileForbidden as e: - return {"message": str(e)}, 403 - except utils.FileNotFound as e: - return {"message": str(e)}, 404 - except utils.AnisServerError as e: - return {"message": str(e)}, 500 - - fig = plot.create_figure(file_path, stretch, pmin, pmax, axes, theme) - output = io.BytesIO() - fig.save(output, format="png") - - return Response(output.getvalue(), mimetype='image/png') - -@app.route('/spectra-to-csv/<dname>') -def spectra_to_csv(dname): - filename = request.args.get('filename', default=None) - if filename is None: - return {"message": "Parameter filename is mandatory"}, 400 - - try: - file_path = utils.get_file_path(dname, filename) - csv = spectra.spectra_to_csv(file_path, filename) - except utils.DatasetNotFound as e: - return {"message": str(e)}, 404 - except utils.FileForbidden as e: - return {"message": str(e)}, 403 - except utils.FileNotFound as e: - return {"message": str(e)}, 404 - except utils.AnisServerError as e: - return {"message": str(e)}, 500 - - return Response(csv, mimetype='text/csv') +def create_app(): + utils.check_config() + + app = Flask(__name__) + CORS(app) + + @app.route('/') + def index(): + return { + "message": "it works!" + } + + @app.route('/get-fits-image-limits/<dname>') + def get_fits_image_limits(dname): + filename = request.args.get('filename', default=None) + if filename is None: + return {"message": "Parameter filename is mandatory"}, 400 + + try: + file_path = utils.get_file_path(dname, filename) + except utils.DatasetNotFound as e: + return {"message": str(e)}, 404 + except utils.FileForbidden as e: + return {"message": str(e)}, 403 + except utils.FileNotFound as e: + return {"message": str(e)}, 404 + except utils.AnisServerError as e: + return {"message": str(e)}, 500 + + return cut.getImageLimits(file_path) + + @app.route('/fits-cut/<dname>') + def fits_cut(dname): + filename = request.args.get('filename', default=None) + if filename is None: + return {"message": "Parameter filename is mandatory"}, 400 + + ra = float(request.args.get('ra', '')) + dec = float(request.args.get('dec', '')) + radius = float(request.args.get('radius', '')) + + if ra is None: + return {"message": "Parameter ra is mandatory"}, 400 + if dec is None: + return {"message": "Parameter dec is mandatory"}, 400 + if radius is None: + return {"message": "Parameter radius is mandatory"}, 400 + + try: + file_path = utils.get_file_path(dname, filename) + except utils.DatasetNotFound as e: + return {"message": str(e)}, 404 + except utils.FileForbidden as e: + return {"message": str(e)}, 403 + except utils.FileNotFound as e: + return {"message": str(e)}, 404 + except utils.AnisServerError as e: + return {"message": str(e)}, 500 + + fits_file = cut.fits_cut(file_path, ra, dec, radius) + + output = io.BytesIO() + fits_file.writeto(output, overwrite=True) + return Response(output.getvalue(), mimetype='image/fits') + + @app.route('/fits-cut-to-png/<dname>') + def fits_cut_to_png(dname): + filename = request.args.get('filename', default=None) + if filename is None: + return {"message": "Parameter filename is mandatory"}, 400 + + ra = request.args.get('ra', default=None, type=float) + dec = request.args.get('dec', default=None, type=float) + radius = request.args.get('radius', default=None, type=float) + stretch = request.args.get('stretch', default=None) + pmin = request.args.get('pmin', default=None, type=float) + pmax = request.args.get('pmax', default=None, type=float) + axes = request.args.get('axes', default=None) + theme = request.args.get('theme', default=None) + + if ra is None: + return {"message": "Parameter ra is mandatory"}, 400 + if dec is None: + return {"message": "Parameter dec is mandatory"}, 400 + if radius is None: + return {"message": "Parameter radius is mandatory"}, 400 + if stretch is None: + return {"message": "Parameter stretch is mandatory"}, 400 + if pmin is None: + return {"message": "Parameter pmin is mandatory"}, 400 + if pmax is None: + return {"message": "Parameter pmax is mandatory"}, 400 + if axes is None: + return {"message": "Parameter axes is mandatory"}, 400 + + try: + file_path = utils.get_file_path(dname, filename) + except utils.DatasetNotFound as e: + return {"message": str(e)}, 404 + except utils.FileForbidden as e: + return {"message": str(e)}, 403 + except utils.FileNotFound as e: + return {"message": str(e)}, 404 + except utils.AnisServerError as e: + return {"message": str(e)}, 500 + + fits_file = cut.fits_cut(file_path, ra, dec, radius) + + output = io.BytesIO() + fig = plot.create_figure(fits_file, stretch, pmin, pmax, axes, theme) + if axes == 'true': + fig.savefig(output, format="png") + else: + fig.savefig(output, format="png", bbox_inches='tight', pad_inches = 0) + + return Response(output.getvalue(), mimetype='image/png') + + @app.route('/fits-to-png/<dname>') + def fits_to_png(dname): + filename = request.args.get('filename', default=None) + if filename is None: + return {"message": "Parameter filename is mandatory"}, 400 + + stretch = request.args.get('stretch', default=None) + pmin = request.args.get('pmin', default=None, type=float) + pmax = request.args.get('pmax', default=None, type=float) + axes = request.args.get('axes', default=None) + theme = request.args.get('theme', default=None) + + try: + file_path = utils.get_file_path(dname, filename) + except utils.DatasetNotFound as e: + return {"message": str(e)}, 404 + except utils.FileForbidden as e: + return {"message": str(e)}, 403 + except utils.FileNotFound as e: + return {"message": str(e)}, 404 + except utils.AnisServerError as e: + return {"message": str(e)}, 500 + + fig = plot.create_figure(file_path, stretch, pmin, pmax, axes, theme) + output = io.BytesIO() + fig.save(output, format="png") + + return Response(output.getvalue(), mimetype='image/png') + + @app.route('/spectra-to-csv/<dname>') + def spectra_to_csv(dname): + filename = request.args.get('filename', default=None) + if filename is None: + return {"message": "Parameter filename is mandatory"}, 400 + + try: + file_path = utils.get_file_path(dname, filename) + csv = spectra.spectra_to_csv(file_path, filename) + except utils.DatasetNotFound as e: + return {"message": str(e)}, 404 + except utils.FileForbidden as e: + return {"message": str(e)}, 403 + except utils.FileNotFound as e: + return {"message": str(e)}, 404 + except utils.AnisServerError as e: + return {"message": str(e)}, 500 + + return Response(csv, mimetype='text/csv') + + return app if __name__ == "__main__": try: - utils.check_config() + app = create_app() app.run(host="0.0.0.0") except utils.ConfigKeyNotFound as e: app.logger.error("Config error") -- GitLab