Celery: рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рд╢рдЯрдбрд╛рдЙрди рдкрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд░рджреНрдж/рдирд┐рд░рд╕реНрдд рдХрд░рдирд╛

рдХреЛ рдирд┐рд░реНрдорд┐рдд 24 рдлрд╝рд░ре░ 2016  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: celery/celery

рдореИрдВ 3.1.20 (рд░реЗрдбрд┐рд╕ рдмреНрд░реЛрдХрд░ рдФрд░ рдмреИрдХрдПрдВрдб) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдЬрдм рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдмрдВрдж рд╣реЛ рд░рд╣рд╛ рд╣реИ рддреЛ рдореИрдВ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдЪрд▓ рд░рд╣реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдирд┐рд░рд╕реНрдд/рдирд┐рд░рд╕реНрдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред
рдореБрджреНрджрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдпрджрд┐ рд╕рдВрднрд╡ рд╣реЛ рддреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ FAILED рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░реЗрдВ, рдФрд░ рдЕрдЧрд▓реА рдмрд╛рд░ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЗ рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рд╣реЛрдиреЗ рдкрд░ рдЙрдиреНрд╣реЗрдВ рдлрд┐рд░ рд╕реЗ рди рдЪрд▓рд╛рдПрдВред

рдореИрдВ рдПрдХ рд╕рдордп рдореЗрдВ рдПрдХ рдХрд╛рд░реНрдп рдЪрд▓рд╛ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдЪреВрдВрдХрд┐ рдХрд╛рд░реНрдп рдХрд╛ рджреБрд╖реНрдкреНрд░рднрд╛рд╡ рд╣реИ (рдФрд░ рдореИрдВ рдЗрд╕реЗ рдмрджрд▓ рдирд╣реАрдВ рд╕рдХрддрд╛), рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЛ рдорд╛рд░рдирд╛ рдЕрдкреЗрдХреНрд╖рд┐рдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реЛрдЧрд╛ рдЬрдм рдХреБрдЫ рдЧрд▓рдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдореИрдВ рдирд╣реАрдВ рдЪрд╛рд╣рддрд╛ рдХрд┐ рдХрд╛рд░реНрдп рдХреЛ рдлрд┐рд░ рд╕реЗ рдЪрд▓рд╛рдпрд╛ рдЬрд╛рдП рдЬрдм рдореИрдВ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реВрдВ (рдореБрдЭреЗ рд╡рд┐рд╢реНрд╡рд╛рд╕ рд╣реИ рдХрд┐ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕рд┐рдШрдВрдбрд▓рд░ рд╡реНрдпрд╡рд╣рд╛рд░ ...)

рдореИрдВрдиреЗ рд╕рдлрд▓рддрд╛ рдХреЗ рдмрд┐рдирд╛ http://stackoverflow.com/a/8230470 рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИред
рдФрд░ рдореИрдВрдиреЗ рдмреВрдЯрд╕реНрдЯреЗрдк рд╕реЗ рдирд┐рдпрдВрддреНрд░рдг рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдпрд╛ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреБрдЫ рдЪреАрдЬреЛрдВ рдХреА рднреА рдХреЛрд╢рд┐рд╢ рдХреА:

from celery import Celery, bootsteps
from celery.task.control import revoke

# TODO : configuration for tests...
class BootPyrosNode(bootsteps.StartStopStep):

    def __init__(self, worker, **kwargs):
        logging.warn('{0!r} is starting from {1}'.format(worker, __file__))

        [...]

    def create(self, worker):
        return self

    def start(self, worker):
        # our step is started together with all other Worker/Consumer
        # bootsteps.
        pass  # not sure in which process this is run.

    def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting abort of current tasks...'.format(worker))
        for req in worker.state.active_requests:
            # worker.app.control.revoke(req.id, terminate=True) # not working
            # revoke(req.id, terminate=True) # not working
        self.node_proc.shutdown()

рдЗрд╕ рддрд░рд╣ рд╕реНрдерд╛рдкрд┐рдд:

celeros_app = Celery()

# setting up custom bootstep to start ROS node and pass ROS arguments to it
celeros_app.steps['worker'].add(BootPyrosNode)
celeros_app.user_options['worker'].add(Option('-R', '--ros-arg', action="append", help='Arguments for ros initialisation'))

рд╣рд╛рд▓рд╛рдВрдХрд┐ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдореЗрд░реЗ рдХрд╛рд░реНрдп рдХреЛ рдирд┐рд░рд╕реНрдд/рдирд┐рд░рд╕реНрдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, (рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рд░реБрдХрдиреЗ рдХреЗ рдмрд╛рдж рдирд┐рдпрдВрддреНрд░рдг рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реЛ?) рдФрд░ рдореИрдВ рд╡рд┐рдЪрд╛рд░реЛрдВ рд╕реЗ рдмрд╛рд╣рд░ рд╣реЛ рд░рд╣рд╛ рд╣реВрдВред

рдпрджрд┐ рдЖрдк рдФрд░ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдХреЛрдб рдпрд╣рд╛рдВ рд╕реЗ рдЖрддрд╛ рд╣реИ: https://github.com/asmodehn/celerosред

рдХреНрдпрд╛ рдХреЛрдИ рд░рд╛рд╕реНрддрд╛ рд╣реИ, рдпрд╛ рдпрд╣ рдПрдХ рдЕрдиреБрдХреВрд▓рди рд╣реИ рдЬреЛ рдЕрднреА рддрдХ рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИ?

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдзрдиреНрдпрд╡рд╛рдж !
рдореИрдВ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рд╢рдЯрдбрд╛рдЙрди рдкрд░ рдЪрд▓ рд░рд╣реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд░рджреНрдж рдХрд░рдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣рд╛ред :

def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting termination of current tasks...'.format(worker))

        # Following code from worker.control.revoke

        task_ids = []
        terminated = set()

        # cleaning all reserved tasks since we are shutting down
        signum = _signals.signum('TERM')
        for request in [r for r in worker.state.reserved_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)

        # Aborting currently running tasks, and triggering soft timeout exception to allow task to clean up.
        signum = _signals.signum('USR1')
        for request in [r for r in worker.state.active_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)  # triggering SoftTimeoutException in Task

        if terminated:
            terminatedstr = ', '.join(task_ids)
            logger.info('Tasks flagged as revoked: %s', terminatedstr)

        self.node_proc.shutdown()

рдкрд╣рд▓реЗ рдореИрдВ рдХрд┐рд╕реА рднреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд╛рд░реНрдп рдХреЛ рд╢рдЯрдбрд╛рдЙрди рд╕реЗ рдареАрдХ рдкрд╣рд▓реЗ рд▓реЗрдиреЗ рд╕реЗ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд░рдХреНрд╖рд┐рдд_рдЕрдиреБрд░реЛрдз рд╕реВрдЪреА рдореЗрдВ рдХрд╛рд░реНрдп рдХреЛ рд░рджреНрдж рдХрд░ рджреЗрддрд╛ рд╣реВрдВред

рдлрд┐рд░ рдореИрдВ рд╕рдХреНрд░рд┐рдп рдЕрдиреБрд░реЛрдз рдХреЛ рдирд┐рд░рд╕реНрдд рдХрд░рддрд╛ рд╣реВрдВ, рдФрд░ рдлрд┐рд░ рдореИрдВ рдХрд╛рд░реНрдп рдореЗрдВ рдПрдХ рд╕рдлрд╛рдИ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдореЗрдВ SoftTimeLimitExceeded рдЕрдкрд╡рд╛рдж рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реВрдВред рдЪреВрдВрдХрд┐ рдореИрдВ acks_late (рдПрдХ рд╕рдордп рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдХрд╛рд░реНрдп рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдореБрдЭреЗ рдЗрд╕реЗ рдареАрдХ рд╕реЗ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рд╕реЗ рд╡рд╛рдкрд╕ рд▓реМрдЯрдиреЗ рдпрд╛ рдмрдврд╝рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдФрд░ рдЕрдЧрд▓реА рдмрд╛рд░ рдЬрдм рдореИрдВ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдЗрд╕реЗ рдкреБрдирд░рд╛рд░рдВрдн рдирд╣реАрдВ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИред

рдореИрдВ рдирд┐рд░рд╕реНрдд рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдЬрдм рдХреЛрдИ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЬрд╛рдирдмреВрдЭрдХрд░ рдХрд┐рд╕реА рдХрд╛рд░реНрдп рдХреЛ рд░рджреНрдж рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ, рддреЛ рдирд┐рд░рд╕реНрдд рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдХреЛрдбрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рдХреБрдЫ рдЬрдЯрд┐рд▓/рд▓рдВрдмреА рд╕рдлрд╛рдИ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдпрд╣ рдорд╛рдорд▓рд╛ рдЕрдзрд┐рдХ рд╣реИ рдЬреИрд╕реЗ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдмрдВрдж рд╣реЛ рд░рд╣рд╛ рд╣реИ, рдФрд░ рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдореИрдВ рд╡рд░реНрддрдорд╛рди рдХрд╛рд░реНрдп рдХреЛ рдЬрд▓реНрджреА рд╕реЗ рд╡рд┐рдлрд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЕрдЬрд╡рд╛рдЗрди рдореЗрдВ рдЪреАрдЬреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХрд╛ рдпрд╣ рдПрдХ рдЙрдЪрд┐рдд рддрд░реАрдХрд╛ рд╣реЛрдЧрд╛?

рднрд╡рд┐рд╖реНрдп рдХреЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдХрд╛рд░реНрдп рд╡рд░реНрдЧ рдореЗрдВ рдПрдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ ... рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП on_revoke() рдпрд╛ on_abort() рд╡рд┐рдзрд┐ рдХреЛ рдЕрдзрд┐рднрд╛рд░рд┐рдд рдХрд░реЗрдВред рдФрд░ рд╢рд╛рдпрдж рдХреБрдЫ рд╢рд░реНрддреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдирд┐рд░рд╕реНрдд рдХрд░рдиреЗ рдкрд░ рдПрдХрд╛рдзрд┐рдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ ...
рдмрд╕ рдореЗрд░реЗ 2 рд╕реЗрдВрдЯ, рдореИрдВрдиреЗ рдЕрднреА рддрдХ рд╕реЗрд▓реЗрд░реА v4.0 рдХреА рдЬрд╛рдБрдЪ рдирд╣реАрдВ рдХреА рд╣реИред

рд╕рднреА 3 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЖрдк рд╢рдЯрдбрд╛рдЙрди рдХреЗ рджреМрд░рд╛рди рдЕрдкрдиреЗ рдЖрдк рдХреЛ рд░рд┐рдореЛрдЯ рдХрдВрдЯреНрд░реЛрд▓ рдХрдорд╛рдВрдб рдирд╣реАрдВ рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВ, рдЖрдкрдХреЛ рд╡рд░реНрдХрд░ рдЗрдВрдЯрд░реНрдирд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд░рджреНрдж рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рджреЗрдЦреЗрдВ рдХрд┐ рд╕реЗрд▓реЗрд░реА/рд╡рд░реНрдХрд░/рдХрдВрдЯреНрд░реЛрд▓.py рдореЗрдВ рд░рд┐рдореЛрдЯ рдХрдВрдЯреНрд░реЛрд▓ рдХрдорд╛рдВрдб рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ)ред

рдЖрдкрдХреЛ рд╢рд╛рдпрдж рдпрд╣ рднреА рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЖрдкрдХрд╛ рдмреВрдЯрд╕реНрдЯреЗрдк рдкреВрд▓ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ, рддрд╛рдХрд┐ рд╢рдЯрдбрд╛рдЙрди рдХреЗ рджреМрд░рд╛рди рдЖрдкрдХреА stop() рд╡рд┐рдзрд┐ рдХреЛ рдкрд╣рд▓реЗ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ:

class Step..:
    requires = ('celery.worker.components:Pool',)

рдзрдиреНрдпрд╡рд╛рдж !
рдореИрдВ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рд╢рдЯрдбрд╛рдЙрди рдкрд░ рдЪрд▓ рд░рд╣реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд░рджреНрдж рдХрд░рдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣рд╛ред :

def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting termination of current tasks...'.format(worker))

        # Following code from worker.control.revoke

        task_ids = []
        terminated = set()

        # cleaning all reserved tasks since we are shutting down
        signum = _signals.signum('TERM')
        for request in [r for r in worker.state.reserved_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)

        # Aborting currently running tasks, and triggering soft timeout exception to allow task to clean up.
        signum = _signals.signum('USR1')
        for request in [r for r in worker.state.active_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)  # triggering SoftTimeoutException in Task

        if terminated:
            terminatedstr = ', '.join(task_ids)
            logger.info('Tasks flagged as revoked: %s', terminatedstr)

        self.node_proc.shutdown()

рдкрд╣рд▓реЗ рдореИрдВ рдХрд┐рд╕реА рднреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд╛рд░реНрдп рдХреЛ рд╢рдЯрдбрд╛рдЙрди рд╕реЗ рдареАрдХ рдкрд╣рд▓реЗ рд▓реЗрдиреЗ рд╕реЗ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд░рдХреНрд╖рд┐рдд_рдЕрдиреБрд░реЛрдз рд╕реВрдЪреА рдореЗрдВ рдХрд╛рд░реНрдп рдХреЛ рд░рджреНрдж рдХрд░ рджреЗрддрд╛ рд╣реВрдВред

рдлрд┐рд░ рдореИрдВ рд╕рдХреНрд░рд┐рдп рдЕрдиреБрд░реЛрдз рдХреЛ рдирд┐рд░рд╕реНрдд рдХрд░рддрд╛ рд╣реВрдВ, рдФрд░ рдлрд┐рд░ рдореИрдВ рдХрд╛рд░реНрдп рдореЗрдВ рдПрдХ рд╕рдлрд╛рдИ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдореЗрдВ SoftTimeLimitExceeded рдЕрдкрд╡рд╛рдж рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реВрдВред рдЪреВрдВрдХрд┐ рдореИрдВ acks_late (рдПрдХ рд╕рдордп рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдХрд╛рд░реНрдп рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдореБрдЭреЗ рдЗрд╕реЗ рдареАрдХ рд╕реЗ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рд╕реЗ рд╡рд╛рдкрд╕ рд▓реМрдЯрдиреЗ рдпрд╛ рдмрдврд╝рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдФрд░ рдЕрдЧрд▓реА рдмрд╛рд░ рдЬрдм рдореИрдВ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдЗрд╕реЗ рдкреБрдирд░рд╛рд░рдВрдн рдирд╣реАрдВ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИред

рдореИрдВ рдирд┐рд░рд╕реНрдд рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдЬрдм рдХреЛрдИ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЬрд╛рдирдмреВрдЭрдХрд░ рдХрд┐рд╕реА рдХрд╛рд░реНрдп рдХреЛ рд░рджреНрдж рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ, рддреЛ рдирд┐рд░рд╕реНрдд рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдХреЛрдбрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рдХреБрдЫ рдЬрдЯрд┐рд▓/рд▓рдВрдмреА рд╕рдлрд╛рдИ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдпрд╣ рдорд╛рдорд▓рд╛ рдЕрдзрд┐рдХ рд╣реИ рдЬреИрд╕реЗ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдмрдВрдж рд╣реЛ рд░рд╣рд╛ рд╣реИ, рдФрд░ рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдореИрдВ рд╡рд░реНрддрдорд╛рди рдХрд╛рд░реНрдп рдХреЛ рдЬрд▓реНрджреА рд╕реЗ рд╡рд┐рдлрд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЕрдЬрд╡рд╛рдЗрди рдореЗрдВ рдЪреАрдЬреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХрд╛ рдпрд╣ рдПрдХ рдЙрдЪрд┐рдд рддрд░реАрдХрд╛ рд╣реЛрдЧрд╛?

рднрд╡рд┐рд╖реНрдп рдХреЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдХрд╛рд░реНрдп рд╡рд░реНрдЧ рдореЗрдВ рдПрдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ ... рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП on_revoke() рдпрд╛ on_abort() рд╡рд┐рдзрд┐ рдХреЛ рдЕрдзрд┐рднрд╛рд░рд┐рдд рдХрд░реЗрдВред рдФрд░ рд╢рд╛рдпрдж рдХреБрдЫ рд╢рд░реНрддреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдирд┐рд░рд╕реНрдд рдХрд░рдиреЗ рдкрд░ рдПрдХрд╛рдзрд┐рдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ ...
рдмрд╕ рдореЗрд░реЗ 2 рд╕реЗрдВрдЯ, рдореИрдВрдиреЗ рдЕрднреА рддрдХ рд╕реЗрд▓реЗрд░реА v4.0 рдХреА рдЬрд╛рдБрдЪ рдирд╣реАрдВ рдХреА рд╣реИред

рдЗрд╕ рдкрд░ рдХрд┐рд╕реА рднреА рдЕрджреНрдпрддрди?

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

aTylerRice picture aTylerRice  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

myisis picture myisis  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

kgritesh picture kgritesh  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

keisetsu picture keisetsu  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

croth1 picture croth1  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ