решено: выясняется, что проблема возникает из-за предварительной загрузки оружия и разветвления против апшедулера. См. Комментарий.
Фон
Я пишу простой API фляги, который выполняет периодический фоновый запрос к базе данных SQL с помощью apscheduler, а затем обрабатывает входящие запросы отдыха с помощью фляги. API будет выполнять различное агрегирование в зависимости от входящего запроса.
У меня есть объект класса данных, который имеет методы для 1) запроса / обновления, 2) ответа на запросы агрегации. Проблема возникает, когда ресурс фляги как-то застревает в более старой версии данных, а журналы показывают, что метод запроса / обновления был вызван правильно.
Код до сих пор
Я сломалзагрузите мое приложение в модули следующим образом:
app/
├── app.py
└── apis
├── __init__.py
└── model1.py
Файл модели данных
В model1.py
я определил класс данных, конечные точки API с пространством имен flask-restplus
и инициализировал данныеобъект:
from flask_restplus import Namespace, Resource
import pandas as pd
api = Namespace('sales')
@api.route('/check')
class check_sales(Resource):
def post(self):
import json
req = api.payload
result = data.get_sales(**req)
return result, 200
class sales_today():
def __init__(self):
self.data = None
self.update()
def update(self):
# some logging here
self.data = self.check_sql()
logging.debug("Last Order: %s" % str(self.data.sales_time.max()))
def check_sql(self):
query = """
SELECT region, store, item, sales_count, MAX(UtcTimeStamp) as sales_time FROM db GROUP BY 1,2,3
"""
sales = pd.read_gbq(query)
return sales
def get_sales(self, **kwargs):
'''
kwargs here is a dict where we filter and sum
'''
for arg_name in (x for x in kwargs):
mask = True
if type(kwargs[arg_name]) is str:
arg_value = kwargs[arg_name].split(',')
mask = mask & (self.data[arg_name].isin(arg_value))
result = {k:v for k,v in kwargs.items()}
result['count'] = int(self.data.loc[mask]['sales_count'])
result['last_updated'] = str(self.data.sales_time.max())
return result
data = sales_today()
Файл инициализации модуля
В __init__.py
внутри app/apis
Я передаю экземпляр объекта данных, а также пространство имен API.
from .model1 import api as ns_model1
from .model1 import data as data_model1
def add_apins(api):
api.add_namespace(ns_model1, path='/model1')
Основной файл приложения
В основном файле app.py
я размещаю планировщик так, чтобы данные обновлялись каждые 5 минут с помощью apscheduler
. Затем я работаю с этим приложением с gunicorn.
import atexit
from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask
from flask_restplus import Resource, Api
from apis import add_apins
from apis import data_model1
# parameters
port = 8888
poll_freq = '0-59/5'
# flask app
main_app = Flask(__name__)
api = Api()
add_apins(api)
api.init_app(main_app)
# background scheduler
sched = BackgroundScheduler()
sched.add_job(data_model1.update, 'cron', minute=poll_freq)
sched.start()
atexit.register(lambda: sched.shutdown(wait=False))
if __name__ == "__main__":
# serve(application, host='0.0.0.0', port=port) # ssl_context="adhoc" for https testing locally
run_simple(application=main_app, hostname='0.0.0.0', port=port, use_debugger=True)
Ожидание и проблемы
Поскольку запрос обновляется каждые 5 минут, я буду ожидать, когда я запрашиваю конечную точку /check
, отвечающую полезную нагрузкуЗначение last_updated
будет соответствовать последним из журналов (строка logging.debug
в методе update()
). Тем не менее, я получаю ответы, указывающие, что значение last_updated
равно тому, когда приложение запускалось изначально.
Я подтвердил в БД, что данные там действительно актуальны, и из журнала яm также подтвердил, что метод update()
запускается каждые 5 минут и показывает последнюю метку времени.
Я также заметил, что приложение отлично работает с python app.py
в Windows, но при запуске приложения с gunicorn он начинает демонстрировать это странное поведение.
Я совершенно озадачен тем, где что-то идет не так. Это может быть область видимости? Или я неправильно передаю экземпляр между модулями?
Большое вам спасибо за ваше время и помощь. Любые идеи будут высоко оценены.