pomponchik / cantok

Implementation of the "Cancellation Token" pattern
http://cantok.readthedocs.io/
MIT License
113 stars 6 forks source link

Можно использовать cantok для отмены операции из другого сервиса, если общение между сервисами, через шину #32

Closed Barolina closed 7 months ago

Barolina commented 7 months ago

Очень интересный доклад, первый раз услышала, про такой подход.

И возник вопрос, по use case:

Есть два сервиса, общающиеся через шину. Второй сервис, выполнят pipline действия, достаточно продолжительно. Как можно применить этот подход, для отмены операции, из первого сервиса?

И может, я не совсем поняла, где хранятся эти токены?

pomponchik commented 7 months ago

Привет!

Токены "хранятся" внутри оперативной памяти. По сути это обычные объекты, которые могут отвечать да или нет на вопрос "отменена ли операция?".

В твоем случае токен во втором сервисе должен как-то узнать о том, что пора завершаться. Я вижу несколько вариантов, как это можно сделать:

  1. Использовать ConditionToken, передав ему некоторую функцию, которая будет узнавать у первого сервиса, продолжать ли работу. У этого варианта есть минус, если ваши сервисы взаимодействуют по сети, то они могут начать заметно тормозить, ведь каждый раз, когда код второго сервиса захочет узнать, не остановлен ли он, будет выполняться дорогостоящий сетевой вызов.

  2. Использовать токен отмены, но по более сложной и умной стратегии. Тебе нужна штука во втором сервисе, которая будет по расписанию (например, раз в секунду) ходить в первый сервис и уточнять, продолжать ли работу. Когда первый сервис ответит, что не продолжать - эта штука должна отменить корневой токен во втором сервисе.

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

import json

import requests
from metronomes import Metronome
from cantok import SimpleToken

from another_module import do_real_stuff

THE_FIRST_SERVICE_ADDRESS = 'https://first_service_url.com'

def run_heavy_task_in_the_second_service():
    token = SimpleToken()

    def is_the_second_service_stopped():
        if json.loads(requests.get(THE_FIRST_SERVICE_ADDRESS).text)['am_i_cancelled']:
            token.cancel()

    with Metronome(1, is_the_second_service_stopped):
        do_real_stuff(token)
  1. Первый сервис может передать второму таймаут как число, а второй на основе этого числа создаст объект TimeoutToken.
Barolina commented 7 months ago

Привет!

Токены "хранятся" внутри оперативной памяти. По сути это обычные объекты, которые могут отвечать да или нет на вопрос "отменена ли операция?".

В твоем случае токен во втором сервисе должен как-то узнать о том, что пора завершаться. Я вижу несколько вариантов, как это можно сделать:

  1. Использовать ConditionToken, передав ему некоторую функцию, которая будет узнавать у первого сервиса, продолжать ли работу. У этого варианта есть минус, если ваши сервисы взаимодействуют по сети, то они могут начать заметно тормозить, ведь каждый раз, когда код второго сервиса захочет узнать, не остановлен ли он, будет выполняться дорогостоящий сетевой вызов.
  2. Использовать токен отмены, но по более сложной и умной стратегии. Тебе нужна штука во втором сервисе, которая будет по расписанию (например, раз в секунду) ходить в первый сервис и уточнять, продолжать ли работу. Когда первый сервис ответит, что не продолжать - эта штука должна отменить корневой токен во втором сервисе.

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

import json

import requests
from metronomes import Metronome
from cantok import SimpleToken

from another_module import do_real_stuff

THE_FIRST_SERVICE_ADDRESS = 'https://first_service_url.com'

def run_heavy_task_in_the_second_service():
    token = SimpleToken()

    def is_the_second_service_stopped():
        if json.loads(requests.get(THE_FIRST_SERVICE_ADDRESS).text)['am_i_cancelled']:
            token.cancel()

    with Metronome(1, is_the_second_service_stopped):
        do_real_stuff(token)
  1. Первый сервис может передать второму таймаут как число, а второй на основе этого числа создаст объект TimeoutToken.

спасибо за ответы! попробую!