GAE Gunicorn колба лучший способ действовать с запросами, который занимает 30-60 минут - PullRequest
1 голос
/ 20 июня 2019

Я создал приложение с флягой, которое сможет сканировать некоторые данные.Первым шагом является использование API данных Youtube для получения некоторых данных о пользователе, включая список всех видео, которые пользователь когда-либо загружал.Это прекрасно работает!После того, как я получил список идентификаторов видео, я пытаюсь собрать все эти видео на YouTube, чтобы выделить лайки и просмотры по всем видео и собрать их вместе в 2 больших числа.Я проверял это локально без gunicorn и не в движке приложения, он работает отлично!Но когда пользователь загрузил 6700 видео, выполнение запроса может занять 30 минут (локально это работает).enter image description here Когда я пытаюсь запустить тот же код в GAE, он возвращает 502 Bad Gateway через несколько минут, но в журналах я вижу, что он все еще ползает.Это GET 502: 502 Bad Gateway Request

Работник продолжал очищать в течение нескольких минут.End of Logs

Вот код, который я написал для сканирования: Это мой app.yaml.С помощью -t 36000 рабочие могут молчать в течение одного часа, пока их не убьют и не перезапустят.

runtime: python37
service: crawler
entrypoint: . ./env.inc.sh && gunicorn -t 36000 -b :$PORT app:app

Это маршрут в моем app.py, который называется:

@app.route('/youtube/username/<user>')
def youtubeStatistics(user):
    response = crawler.crawl_youtube_user(os.environ['YOUTUBE_API_KEY'], user)
    if response:
        return jsonify(response), 200
    else:
        return jsonify({"prettyMessage": "Quota Limit maybe Exceeded"}), 403

ЭтиИспользуются ли мои функции сканирования:

def scrape_url(url):
    r = requests.get(url)
    page = r.text
    soup = bs(page, 'html.parser')
    return soup

def crawl_youtube_user(KEY, username):
    youtube = set_up(KEY)
    request = youtube.channels().list(
        part="snippet,contentDetails,statistics",
        forUsername=username
    )
    uploadPlaylistId = ""
    data = {}
    try:
        response = request.execute()
    except:
        return {}
    if (response["pageInfo"]["totalResults"] > 0):
        stats = response["items"][0]["statistics"]
        data["subscriberCount"] = stats["subscriberCount"]
        data["videoCount"] = stats["videoCount"]
        data["publishedAt"] = response["items"][0]["snippet"]["publishedAt"]
        uploadPlaylistId = response["items"][0]["contentDetails"]["relatedPlaylists"]["uploads"]
        request = youtube.playlistItems().list(
            part="snippet,contentDetails",
            maxResults=50,
            playlistId=uploadPlaylistId
        )
        videoIds = []
        while True:
            try:
                response = request.execute()
            except:
                return {}
            for vid in response["items"]:
                videoIds.append(vid["snippet"]["resourceId"]["videoId"])
            if "nextPageToken" not in response:
                break
            else:
                request = youtube.playlistItems().list(
                    part="snippet,contentDetails",
                    maxResults=50,
                    playlistId=uploadPlaylistId,
                    pageToken=response["nextPageToken"]
                )
        data.update(crawl_youtube_videos(videoIds))
    return data


def crawl_youtube_videos(ids):
    data = {'viewCount': 0, 'videoLikes': 0}
    counter = 0
    idlength = len(ids)
    for id in ids:
        counter += 1
        print('{}/{}: Scraping Youtube videoId {}'.format(counter,idlength,id))
        soup = scrape_url('https://www.youtube.com/watch?v={}&gl=DE&hl=de'.format(id))
        try:
            data['viewCount'] += int(soup.find('div', class_='watch-view-count').getText().split(' ')[0].replace('.', '').replace(',', ''))
        except:
            print("Error while trying to extract the views of a Video: {}.".format(sys.exc_info()[0]))
        try:
            data['videoLikes'] += int(soup.find("button",{"title": "Mag ich"}).find("span").getText().replace('.', '').replace(',', ''))
        except:
            print("Error while trying to extract the likes of a Video: {}.".format(sys.exc_info()[0]))
    return data

Я не хочу использовать больше потоков или что-то в этом роде, чтобы ускорить весь процесс!Я боюсь, что мой IP будет заблокирован или что-то в этом роде, если я заскочу на многие сайты за короткое время.Я просто пытаюсь сохранить запрос, пока не получу ответ, который хочу.Так есть ли еще механизмы, которые защищают приложение GAE от длительного времени отклика или что-то в этом роде? И как лучше всего реагировать на запросы, которые занимают 30-60 минут?

1 Ответ

1 голос
/ 21 июня 2019

Вам следует рассмотреть возможность использования очереди фоновых задач, например Сельдерей или RQ .

Когда ваш запрос будет принят, он будет помещен в очередь на работу. Затем вы можете запросить очередь задач и получить статус задания по своему усмотрению.

Здесь - отличный ресурс для начала работы с любой из этих опций.

...