Правильный способ передачи экземпляра объекта между модулями - PullRequest
1 голос
/ 30 октября 2019

решено: выясняется, что проблема возникает из-за предварительной загрузки оружия и разветвления против апшедулера. См. Комментарий.

Фон

Я пишу простой 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 он начинает демонстрировать это странное поведение.

Я совершенно озадачен тем, где что-то идет не так. Это может быть область видимости? Или я неправильно передаю экземпляр между модулями?

Большое вам спасибо за ваше время и помощь. Любые идеи будут высоко оценены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...