import os import sys import traceback from typing import Iterable import boto3 import redis import sentry_sdk from apollo_notifications.charts import AppleChart, PushChartsMovesSchema from apollo_notifications.decorators import loop, time_logger from apollo_notifications.main_db import session_scope from apollo_notifications.redis import lock from apollo_notifications.user_data.client import UserDataClient from apollo_push_client import Push, PushClient, PushData from apollo_push_client.exceptions import PushClientError from ddtrace import patch_all, tracer from sentry_sdk.utils import BadDsn from sqlalchemy.exc import SQLAlchemyError from config import config from logger import logger from main_db import get_major_moves if os.environ.get("DATADOG_SERVICE_NAME"): patch_all() else: tracer.enabled = False try: if config.ENVIRONMENT != "local": sentry_sdk.init(dsn=config.SENTRY_DSN, environment=config.ENVIRONMENT) except BadDsn: pass redis_client = redis.StrictRedis(config.REDIS_HOST, config.REDIS_PORT) def process_market(notifications_client: AppleChart, push_client: PushClient, market: str, user_id_list: Iterable[str]): with session_scope() as session: push_client.set_session(session) dates = notifications_client.get_dates(market) if len(dates) != 2: return last, previous = dates push_schema = PushChartsMovesSchema(config, last, market, push_cls=Push, push_data_cls=PushData) existing_messages = notifications_client.get_existing_push_messages(last) moves_tracks_query = get_major_moves(session, notifications_client, market, start_date=last, end_date=previous) filtered_tracks = notifications_client.filter_by_starred_and_active(moves_tracks_query, user_id_list) messages = notifications_client.get_push_messages( filtered_tracks, last, market, push_schema, existing_messages=existing_messages ) logger.info(f"created {len(messages)} messages for {market} market.") push_client.process_messages(messages, push_date=last, save_to_db=True, raise_exc=True) @loop(logger, config) def job( notifications_client: AppleChart, push_client: PushClient, user_data_client: UserDataClient, ) -> None: with session_scope(): markets_to_users_map, user_id_list = user_data_client.parse_v1_mobile_settings(config.VENDOR) markets = notifications_client.get_markets(markets_to_users_map.keys()) logger.info(f"1. Got {len(markets)} active markets: {markets}") for market in markets: try: process_market(notifications_client, push_client, market, markets_to_users_map[market]) except (SQLAlchemyError, PushClientError) as ex: sentry_sdk.capture_exception(ex) logger.error(traceback.format_exception(*sys.exc_info()) + traceback.format_stack()) finally: markets_to_users_map.pop(market) @time_logger(logger, config.APP_NAME) @lock(logger, config, redis_client, sentry=sentry_sdk) def handler(): """Save push messages to db and send them to queue.""" sqs_client = boto3.client("sqs") user_data_client = UserDataClient(config, logger) notifications_client = AppleChart(config) push_client = PushClient(logger_client=logger, sqs_client=sqs_client, config=config) job(notifications_client, push_client, user_data_client) if __name__ == "__main__": handler()