Я пытаюсь решить следующую задачу:Как определить приоритеты задач при использовании очереди задач в движке Google?
- У меня есть ряд «задачи», которые я хотел бы выполнить
- У меня есть определенное количество рабочих для выполнения этих работников (так они называют внешний API с использованием urlfetch и количество параллельных вызовов этого API ограничено)
- Я хотел бы, чтобы эти «задачи» выполнялись «как можно скорее» (то есть минимальная задержка)
- Эти задачи являются частями более крупных задач и может быть классифицирован в зависимости от размера исходной задачи (т. е. небольшая оригинальная задача может генерировать от 1 до 100 задач с, средний от 100 до 1000 и большой - более 1000).
Сложная часть: Я хотел бы сделать все это эффективно (то есть минимальную задержку и использовать как можно больше параллельных API-вызовов - без превышения предела), но в то же время попытаться предотвратить большой количество задач, генерируемых из «больших» исходных задач, для задержки задач, генерируемых из «малых» исходных задач.
Иными словами, я хотел бы иметь «приоритет», назначенный каждой задаче с «маленькими» задачами с более высоким приоритетом и тем самым предотвращать голодание от «больших» задач.
Некоторые искать вокруг, кажется, не показывают, что все готовые доступен, поэтому я придумал следующее:
- создать три нажимные очереди:
tasks-small
,tasks-medium
,tasks-large
- множества а максимальное количество одновременных запросов для каждого из них, так что общее количество является максимальным количеством одновременных вызовов API (например, если максимальный вызов одновременных API составляет 200, я мог бы установить
tasks-small
, чтобы иметьmax_concurrent_requests
из 30,tasks-medium
60 иtasks-large
100) - при постановке на охрану задания, проверьте номер. ожидающую задачи в каждой очереди (используя что-то вроде класса QueueStatistics), и если другая очередь не используется на 100%, запустите там задачу, иначе просто установите задачу в очереди с соответствующим размером.
Например, если мы имеем задачу T1
которая является частью небольшой задачи, первая проверка, если tasks-small
есть свободные «слоты» и епдиеие его там. В противном случае проверьте tasks-medium
и tasks-large
. Если ни один из них не имеет свободных слотов, в любом случае добавьте его на tasks-small
, и он будет обработан после того, как задачи будут добавлены до его обработки (обратите внимание: это не оптимально, потому что если «слоты» освобождаются в других очередях, они все равно не будут обрабатывать незавершенные задачи из очереди tasks-small
)
Другой вариант - использовать очередь PULL и иметь центральный «координатор», который вытаскивает из этой очереди на основе приоритетов и отправляет их, однако это, кажется, добавляет немного больше латентности.
Однако это кажется немного хакерским, и мне интересно, есть ли там лучшие альтернативы.
EDIT: после того, как некоторые мысли и обратной связи я имею в виду использование очереди PULL после того, как все следующим образом:
- имеют два PULL очереди (
medium-tasks
иlarge-tasks
) - имеют диспетчеру (PUSH) с параллелизмом 1 (так что только одна задача отправки запускается в любое время). Задачи диспетчеризации созданы несколькими способами:
- по один раз в минуты хрон
- после добавления средней/большой задачей толкающих очередей
- после задания рабочего заканчивает
- есть очередь работник (PUSH) с параллелизмом, равное числу рабочих
И рабочий процесс:
- мелкие задачи добавляются непосредственно в очередь рабочего
- диспетчер задач, когда он запускается, выполняет следующие действия:
- оценивает количество свободных рабочих (смотря на количество запущенных задач в рабочая очередь)
- для любых «свободных» слотов он берет задачу из средних/больших задач PULL queue и ставит ее в очередь на рабочем месте (точнее: добавляет его в очередь PUSH рабочего, что приведет к ее выполнению - в конечном счете - у рабочего).
Я доложу, как только это будет реализовано, и по крайней мере умеренно протестированы.