Содержание

Назначенная заявка ST_REQUEST: ручное начало работы и автоматический переход

Назначение: Сценарий процесса. Продукт: ShariX Open.

Для кого: Разработчик · Поддержка · Рецензент и приёмщик · Нейросеть.

Темы: Обработчики → ST_REQUEST · Обработчики → Runtime.

Область: ShariX Open. Обработчик: open_st_request_assigned, тип ST_REQUEST (1), рабочий статус ASSIGNED. 31.10.2026 исходники повторно получены из Git. Обе Python-копии совпали с новой канонической генерацией Blockly; проверены 11 исходников генераторов. Сам обработчик и его внешние действия не запускались. Выбранная версия, настройки и доступность подключений конкретной установки проверяются отдельно.

Назначение и границы

Обработчик сопровождает уже назначенную стадию:

Статус ASSIGNED и заполненное поле assigned_to — разные факты. Автоматическое продвижение статуса не назначает исполнителя задним числом. Техническая причина support_execution — локальная отметка runtime, а не комментарий в карточке, не поручение пользователю и не сообщение об успешно выполненной работе.

На диаграммах end event означает завершение конкретного прохода, передачи или текущей операции очереди. Он не означает, что вся заявка закрыта. Схемы описательные: isExecutable=false, они ничего не запускают и не создают таймеров в системе.

Алгоритм обработчика и локальное ожидание (BPMN)

Схема BPMN

Загрузка схемы…

Исходник схемы
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_st_assigned_logic" targetNamespace="urn:sharix:knowledge:handlers">
  <bpmn:process id="assigned_Process_assigned" name="open_st_request_assigned: Python и локальная очередь" isExecutable="false">
    <bpmn:documentation>{"notes": ["Описание Git built-in; реальные локальные версии сверяются отдельно.", "Worker не занят во время defer. Символ deferred_until означает текущий локальный срок.", "Граница ошибки включает ошибку API/отправки, но не отменяет уже зафиксированный переход."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_st_request_assigned.json", "repository": "sharix-open-handlers-examples", "sha256": "d49e943a8806c3130acf09f1e93cf6b4e4a7d6f7428a5d18844a8f64ff619fe6"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_st_request_assigned.py", "repository": "sharix-open-handlers-examples", "sha256": "2be4d63c70b8469e541346aa3185bb29d04af1a87fb64fb1df118bde3ebe3c42"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_st_request_new.json", "repository": "sharix-open-handlers-examples", "sha256": "6b76b94236e6257f1f13dff9f41bb48c47352d5c512c9add0c5e53153c2dd6ff"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_st_request_new.py", "repository": "sharix-open-handlers-examples", "sha256": "f3cc74eccbc60431fff10e4989a4e499af85c7190b2e30cba8b097639cf1a23f"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "utils.py", "repository": "sharix-open-tickets", "sha256": "a5680205c6522e1d9a74d9d267fe9ee96faf6f06436b00877fc0a93d80234bf5"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "views/ticket_detail.py", "repository": "sharix-open-tickets", "sha256": "05d344b0fba14cf895400694d4a18f486c800fef08dd1acb43ea46909b9e7e59"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/views/handler_workflow.py", "repository": "sharix-open-tickets", "sha256": "f97c4b467a9a30749f5c4b86b39a833c430e57aaa1f030f70030d9b5c609d368"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/views/ticket.py", "repository": "sharix-open-tickets", "sha256": "b25a66fc52790f11ba7aca48527a4a5b6640a05ffa377ab58f562955f2695499"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/permissions.py", "repository": "sharix-open-tickets", "sha256": "a0e12d188313ae1e6a9b1502ec48c2dd7f76fffa78ecf50b5b1b33b040b290a1"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "urls.py", "repository": "sharix-open-tickets", "sha256": "c41101b32eb1132d63bf62d5bd96d344a79fe34946dc1635dc090921beb6e3c9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}]}</bpmn:documentation>
    <bpmn:laneSet id="assigned_Lanes_assigned">
      <bpmn:lane id="assigned_Lane_worker" name="Выполнение Python (один проход)">
        <bpmn:flowNodeRef>assigned_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_status</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_auto</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_reason</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_defer</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_cleanup</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_stale_end</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_transition</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_confirmed</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_false_end</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_handoff</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_remove</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_success</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_api_error</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_send_error</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_retry</bpmn:flowNodeRef>
      </bpmn:lane>
      <bpmn:lane id="assigned_Lane_scheduler" name="Планировщик: между проходами, без занятого worker">
        <bpmn:flowNodeRef>assigned_waiting</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_due</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_revision</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>assigned_ready</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="assigned_start" name="Ticket готов к проходу">
      <bpmn:outgoing>assigned_Flow_0</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:exclusiveGateway id="assigned_status" name="Снимок в ASSIGNED?">
      <bpmn:incoming>assigned_Flow_0</bpmn:incoming>
      <bpmn:incoming>assigned_Flow_20</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_1</bpmn:outgoing>
      <bpmn:outgoing>assigned_Flow_2</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:exclusiveGateway id="assigned_auto" name="STREQ_AUTOACCEPT?">
      <bpmn:incoming>assigned_Flow_1</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_4</bpmn:outgoing>
      <bpmn:outgoing>assigned_Flow_7</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="assigned_reason" name="Записать support_execution">
      <bpmn:documentation>Локальная причина ожидания, не комментарий Ticket.</bpmn:documentation>
      <bpmn:incoming>assigned_Flow_4</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_5</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="assigned_defer" name="Назначить повтор проверки">
      <bpmn:documentation>ST_REQUEST_ASSIGNED_RECHECK_SECONDS; вернуть Ticket, освободив worker.</bpmn:documentation>
      <bpmn:incoming>assigned_Flow_5</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_6</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="assigned_cleanup" name="Убрать локальный Ticket и комнату">
      <bpmn:incoming>assigned_Flow_2</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_3</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="assigned_stale_end" name="Этот handler больше не владеет Ticket">
      <bpmn:incoming>assigned_Flow_3</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:serviceTask id="assigned_transition" name="Scoped API: IN_PROCESS">
      <bpmn:documentation>ticket.transition; 404 означает устаревший scope, другие ошибки — исключение.</bpmn:documentation>
      <bpmn:incoming>assigned_Flow_7</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_8</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="assigned_confirmed" name="Переход подтверждён?">
      <bpmn:incoming>assigned_Flow_8</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_9</bpmn:outgoing>
      <bpmn:outgoing>assigned_Flow_10</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:endEvent id="assigned_false_end" name="404: очистка уже запрошена">
      <bpmn:incoming>assigned_Flow_9</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sendTask id="assigned_handoff" name="Передать Ticket в IN_PROCESS handler">
      <bpmn:documentation>open_st_request_inprocess; попытка отправки XMPP, не гарантия завершения следующей стадии.</bpmn:documentation>
      <bpmn:incoming>assigned_Flow_10</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_11</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:serviceTask id="assigned_remove" name="Убрать Ticket; комнату сохранить">
      <bpmn:incoming>assigned_Flow_11</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_12</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="assigned_success" name="Передача текущего handler завершена">
      <bpmn:incoming>assigned_Flow_12</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:boundaryEvent id="assigned_api_error" name="Ошибка API" attachedToRef="assigned_transition" cancelActivity="true">
      <bpmn:outgoing>assigned_Flow_13</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:boundaryEvent id="assigned_send_error" name="Ошибка отправки" attachedToRef="assigned_handoff" cancelActivity="true">
      <bpmn:outgoing>assigned_Flow_14</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:serviceTask id="assigned_retry" name="Ошибка: processing_error и defer">
      <bpmn:documentation>Общий runtime: DEFERRED_TICKET_RECHECK_SECONDS; уже committed status не откатывается.</bpmn:documentation>
      <bpmn:incoming>assigned_Flow_13</bpmn:incoming>
      <bpmn:incoming>assigned_Flow_14</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_15</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:eventBasedGateway id="assigned_waiting" name="Что наступило раньше?">
      <bpmn:incoming>assigned_Flow_6</bpmn:incoming>
      <bpmn:incoming>assigned_Flow_15</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_16</bpmn:outgoing>
      <bpmn:outgoing>assigned_Flow_17</bpmn:outgoing>
    </bpmn:eventBasedGateway>
    <bpmn:intermediateCatchEvent id="assigned_due" name="Текущий срок defer наступил">
      <bpmn:incoming>assigned_Flow_16</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_18</bpmn:outgoing>
      <bpmn:timerEventDefinition>
        <bpmn:timeDate xsi:type="bpmn:tFormalExpression">deferred_until</bpmn:timeDate>
      </bpmn:timerEventDefinition>
    </bpmn:intermediateCatchEvent>
    <bpmn:intermediateCatchEvent id="assigned_revision" name="Подтверждена новая ревизия Ticket">
      <bpmn:documentation>Уже получен новый authoritative snapshot. Дубликат сам по себе не снимает defer.</bpmn:documentation>
      <bpmn:incoming>assigned_Flow_17</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_19</bpmn:outgoing>
      <bpmn:messageEventDefinition />
    </bpmn:intermediateCatchEvent>
    <bpmn:serviceTask id="assigned_ready" name="Снять defer, поставить в ready FIFO">
      <bpmn:documentation>Запуск возможен при готовом XMPP и свободном worker.</bpmn:documentation>
      <bpmn:incoming>assigned_Flow_18</bpmn:incoming>
      <bpmn:incoming>assigned_Flow_19</bpmn:incoming>
      <bpmn:outgoing>assigned_Flow_20</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sequenceFlow id="assigned_Flow_0" sourceRef="assigned_start" targetRef="assigned_status" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_1" sourceRef="assigned_status" targetRef="assigned_auto" name="Да" />
    <bpmn:sequenceFlow id="assigned_Flow_2" sourceRef="assigned_status" targetRef="assigned_cleanup" name="Нет" />
    <bpmn:sequenceFlow id="assigned_Flow_3" sourceRef="assigned_cleanup" targetRef="assigned_stale_end" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_4" sourceRef="assigned_auto" targetRef="assigned_reason" name="Нет" />
    <bpmn:sequenceFlow id="assigned_Flow_5" sourceRef="assigned_reason" targetRef="assigned_defer" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_6" sourceRef="assigned_defer" targetRef="assigned_waiting" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_7" sourceRef="assigned_auto" targetRef="assigned_transition" name="Да" />
    <bpmn:sequenceFlow id="assigned_Flow_8" sourceRef="assigned_transition" targetRef="assigned_confirmed" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_9" sourceRef="assigned_confirmed" targetRef="assigned_false_end" name="Нет (404)" />
    <bpmn:sequenceFlow id="assigned_Flow_10" sourceRef="assigned_confirmed" targetRef="assigned_handoff" name="Да" />
    <bpmn:sequenceFlow id="assigned_Flow_11" sourceRef="assigned_handoff" targetRef="assigned_remove" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_12" sourceRef="assigned_remove" targetRef="assigned_success" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_13" sourceRef="assigned_api_error" targetRef="assigned_retry" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_14" sourceRef="assigned_send_error" targetRef="assigned_retry" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_15" sourceRef="assigned_retry" targetRef="assigned_waiting" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_16" sourceRef="assigned_waiting" targetRef="assigned_due" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_17" sourceRef="assigned_waiting" targetRef="assigned_revision" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_18" sourceRef="assigned_due" targetRef="assigned_ready" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_19" sourceRef="assigned_revision" targetRef="assigned_ready" name="" />
    <bpmn:sequenceFlow id="assigned_Flow_20" sourceRef="assigned_ready" targetRef="assigned_status" name="Новый проход" />
  </bpmn:process>
  <bpmn:collaboration id="Collaboration_st_assigned_logic">
    <bpmn:participant id="assigned_Pool_assigned" name="open_st_request_assigned: Python и локальная очередь" processRef="assigned_Process_assigned" />
  </bpmn:collaboration>
  <bpmndi:BPMNDiagram id="Diagram_st_assigned_logic">
    <bpmndi:BPMNPlane id="Plane_st_assigned_logic" bpmnElement="Collaboration_st_assigned_logic">
      <bpmndi:BPMNShape id="assigned_DI_Pool_assigned" bpmnElement="assigned_Pool_assigned" isHorizontal="true">
        <dc:Bounds x="0.0" y="0.0" width="1880" height="880" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_Lane_worker" bpmnElement="assigned_Lane_worker" isHorizontal="true">
        <dc:Bounds x="30.0" y="0.0" width="1850" height="550.0" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_Lane_scheduler" bpmnElement="assigned_Lane_scheduler" isHorizontal="true">
        <dc:Bounds x="30.0" y="550.0" width="1850" height="330.0" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_start" bpmnElement="assigned_start">
        <dc:Bounds x="142.0" y="102.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_status" bpmnElement="assigned_status">
        <dc:Bounds x="325.0" y="95.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_auto" bpmnElement="assigned_auto">
        <dc:Bounds x="535.0" y="95.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_reason" bpmnElement="assigned_reason">
        <dc:Bounds x="725.0" y="85.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_defer" bpmnElement="assigned_defer">
        <dc:Bounds x="965.0" y="85.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_cleanup" bpmnElement="assigned_cleanup">
        <dc:Bounds x="275.0" y="265.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_stale_end" bpmnElement="assigned_stale_end">
        <dc:Bounds x="542.0" y="282.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_transition" bpmnElement="assigned_transition">
        <dc:Bounds x="725.0" y="265.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_confirmed" bpmnElement="assigned_confirmed">
        <dc:Bounds x="1015.0" y="275.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_false_end" bpmnElement="assigned_false_end">
        <dc:Bounds x="1022.0" y="442.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_handoff" bpmnElement="assigned_handoff">
        <dc:Bounds x="1205.0" y="265.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_remove" bpmnElement="assigned_remove">
        <dc:Bounds x="1445.0" y="265.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_success" bpmnElement="assigned_success">
        <dc:Bounds x="1702.0" y="282.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_api_error" bpmnElement="assigned_api_error">
        <dc:Bounds x="832.0" y="317.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_send_error" bpmnElement="assigned_send_error">
        <dc:Bounds x="1312.0" y="317.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_retry" bpmnElement="assigned_retry">
        <dc:Bounds x="1205.0" y="445.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_waiting" bpmnElement="assigned_waiting">
        <dc:Bounds x="1015.0" y="635.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_due" bpmnElement="assigned_due">
        <dc:Bounds x="1262.0" y="602.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_revision" bpmnElement="assigned_revision">
        <dc:Bounds x="1262.0" y="762.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="assigned_DI_ready" bpmnElement="assigned_ready">
        <dc:Bounds x="1445.0" y="625.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_0" bpmnElement="assigned_Flow_0">
        <di:waypoint x="178.0" y="120.0" />
        <di:waypoint x="325.0" y="120.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_1" bpmnElement="assigned_Flow_1">
        <di:waypoint x="375.0" y="120.0" />
        <di:waypoint x="535.0" y="120.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_2" bpmnElement="assigned_Flow_2">
        <di:waypoint x="350.0" y="145.0" />
        <di:waypoint x="350.0" y="265.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_3" bpmnElement="assigned_Flow_3">
        <di:waypoint x="425.0" y="300.0" />
        <di:waypoint x="542.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_4" bpmnElement="assigned_Flow_4">
        <di:waypoint x="585.0" y="120.0" />
        <di:waypoint x="725.0" y="120.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_5" bpmnElement="assigned_Flow_5">
        <di:waypoint x="875.0" y="120.0" />
        <di:waypoint x="965.0" y="120.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_6" bpmnElement="assigned_Flow_6">
        <di:waypoint x="1115.0" y="120.0" />
        <di:waypoint x="1780.0" y="120.0" />
        <di:waypoint x="1780.0" y="565.0" />
        <di:waypoint x="1040.0" y="565.0" />
        <di:waypoint x="1040.0" y="635.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_7" bpmnElement="assigned_Flow_7">
        <di:waypoint x="585.0" y="120.0" />
        <di:waypoint x="655.0" y="120.0" />
        <di:waypoint x="655.0" y="300.0" />
        <di:waypoint x="725.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_8" bpmnElement="assigned_Flow_8">
        <di:waypoint x="875.0" y="300.0" />
        <di:waypoint x="1015.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_9" bpmnElement="assigned_Flow_9">
        <di:waypoint x="1040.0" y="325.0" />
        <di:waypoint x="1040.0" y="442.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_10" bpmnElement="assigned_Flow_10">
        <di:waypoint x="1065.0" y="300.0" />
        <di:waypoint x="1205.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_11" bpmnElement="assigned_Flow_11">
        <di:waypoint x="1355.0" y="300.0" />
        <di:waypoint x="1445.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_12" bpmnElement="assigned_Flow_12">
        <di:waypoint x="1595.0" y="300.0" />
        <di:waypoint x="1702.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_13" bpmnElement="assigned_Flow_13">
        <di:waypoint x="868.0" y="335.0" />
        <di:waypoint x="900.0" y="335.0" />
        <di:waypoint x="900.0" y="400.0" />
        <di:waypoint x="1280.0" y="400.0" />
        <di:waypoint x="1280.0" y="445.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_14" bpmnElement="assigned_Flow_14">
        <di:waypoint x="1348.0" y="335.0" />
        <di:waypoint x="1400.0" y="335.0" />
        <di:waypoint x="1400.0" y="400.0" />
        <di:waypoint x="1280.0" y="400.0" />
        <di:waypoint x="1280.0" y="445.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_15" bpmnElement="assigned_Flow_15">
        <di:waypoint x="1355.0" y="480.0" />
        <di:waypoint x="1400.0" y="520.0" />
        <di:waypoint x="1040.0" y="520.0" />
        <di:waypoint x="1040.0" y="635.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_16" bpmnElement="assigned_Flow_16">
        <di:waypoint x="1065.0" y="660.0" />
        <di:waypoint x="1163.5" y="660.0" />
        <di:waypoint x="1163.5" y="620.0" />
        <di:waypoint x="1262.0" y="620.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_17" bpmnElement="assigned_Flow_17">
        <di:waypoint x="1065.0" y="660.0" />
        <di:waypoint x="1163.5" y="660.0" />
        <di:waypoint x="1163.5" y="780.0" />
        <di:waypoint x="1262.0" y="780.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_18" bpmnElement="assigned_Flow_18">
        <di:waypoint x="1298.0" y="620.0" />
        <di:waypoint x="1371.5" y="620.0" />
        <di:waypoint x="1371.5" y="660.0" />
        <di:waypoint x="1445.0" y="660.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_19" bpmnElement="assigned_Flow_19">
        <di:waypoint x="1298.0" y="780.0" />
        <di:waypoint x="1371.5" y="780.0" />
        <di:waypoint x="1371.5" y="660.0" />
        <di:waypoint x="1445.0" y="660.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="assigned_DI_Flow_20" bpmnElement="assigned_Flow_20">
        <di:waypoint x="1595.0" y="660.0" />
        <di:waypoint x="1840.0" y="660.0" />
        <di:waypoint x="1840.0" y="45.0" />
        <di:waypoint x="350.0" y="45.0" />
        <di:waypoint x="350.0" y="95.0" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="1525.0" y="15.0" width="180" height="26" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

Сначала проверяется статус локального authoritative-снимка, который очередь получила из backend или входящего Ticket. Отдельный API GET на каждом проходе здесь не выполняется. Если снимок уже не в ASSIGNED, обработчик запрашивает исключение из своей очереди и удаление комнаты уведомлений; сам Ticket в backend этим не удаляется.

Ручной режим, STREQ_AUTOACCEPT выключен:

  1. Записать локальную причину support_execution.
  2. Назначить defer по ST_REQUEST_ASSIGNED_RECHECK_SECONDS.
  3. Освободить текущий worker.
  4. После срока Ticket снова может попасть в ready FIFO; новая подтверждённая ревизия может снять ожидание раньше.

Фактический запуск зависит от worker и XMPP. Повтор одинакового снимка не является новым решением и не обнуляет defer.

Автоматический режим:

  1. Запросить IN_PROCESS через scoped ticket.transition.
  2. После успешного ответа API выполнить send_to_handler в open_st_request_inprocess.
  3. Убрать Ticket из текущей очереди с delete_room=False.

Это передача следующей стадии, а не подтверждение выполнения заявки. Значение STREQ_AUTOACCEPT берётся при создании HandlerContext; сохранение нового значения в файле не доказывает его применения работающим процессом.

Если scoped API вернул 404, runtime трактует снимок как больше не принадлежащий этому обработчику, запрашивает очистку и не делает handoff. Другие ошибки API и ошибки XMPP-отправки проходят через общий error recovery: фиксируется processing_error, назначается defer по DEFERRED_TICKET_RECHECK_SECONDS, ошибка попадает в диагностику. Если переход уже committed, ошибка отправки не возвращает статус в ASSIGNED.

Ручное начало работы и внешние участники (BPMN)

Схема BPMN

Загрузка схемы…

Исходник схемы
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_st_assigned_external" targetNamespace="urn:sharix:knowledge:handlers">
  <bpmn:process id="person_Process_person" name="Пользователь с доступом к Ticket и правом смены статуса" isExecutable="false">
    <bpmn:documentation>{"notes": ["Ручной переход показан отдельно от автоматического.", "Все сообщения backend отправляются после commit; доставка best effort через ejabberd.", "ticket.changed адресуется новому владельцу; ticket.moved прежнему. Потерю сообщения восстанавливает periodic reconciliation."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_st_request_assigned.json", "repository": "sharix-open-handlers-examples", "sha256": "d49e943a8806c3130acf09f1e93cf6b4e4a7d6f7428a5d18844a8f64ff619fe6"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_st_request_assigned.py", "repository": "sharix-open-handlers-examples", "sha256": "2be4d63c70b8469e541346aa3185bb29d04af1a87fb64fb1df118bde3ebe3c42"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_st_request_new.json", "repository": "sharix-open-handlers-examples", "sha256": "6b76b94236e6257f1f13dff9f41bb48c47352d5c512c9add0c5e53153c2dd6ff"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_st_request_new.py", "repository": "sharix-open-handlers-examples", "sha256": "f3cc74eccbc60431fff10e4989a4e499af85c7190b2e30cba8b097639cf1a23f"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "utils.py", "repository": "sharix-open-tickets", "sha256": "a5680205c6522e1d9a74d9d267fe9ee96faf6f06436b00877fc0a93d80234bf5"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "views/ticket_detail.py", "repository": "sharix-open-tickets", "sha256": "05d344b0fba14cf895400694d4a18f486c800fef08dd1acb43ea46909b9e7e59"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/views/handler_workflow.py", "repository": "sharix-open-tickets", "sha256": "f97c4b467a9a30749f5c4b86b39a833c430e57aaa1f030f70030d9b5c609d368"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/views/ticket.py", "repository": "sharix-open-tickets", "sha256": "b25a66fc52790f11ba7aca48527a4a5b6640a05ffa377ab58f562955f2695499"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/permissions.py", "repository": "sharix-open-tickets", "sha256": "a0e12d188313ae1e6a9b1502ec48c2dd7f76fffa78ecf50b5b1b33b040b290a1"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "urls.py", "repository": "sharix-open-tickets", "sha256": "c41101b32eb1132d63bf62d5bd96d344a79fe34946dc1635dc090921beb6e3c9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}]}</bpmn:documentation>
    <bpmn:laneSet id="person_Lanes_person">
      <bpmn:lane id="person_Lane_user" name="Карточка Ticket / пользовательский API">
        <bpmn:flowNodeRef>person_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>person_open</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>person_request</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>person_end</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="person_start" name="Решение начать работу">
      <bpmn:outgoing>person_Flow_0</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:userTask id="person_open" name="Открыть Ticket, выбрать IN_PROCESS">
      <bpmn:incoming>person_Flow_0</bpmn:incoming>
      <bpmn:outgoing>person_Flow_1</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:sendTask id="person_request" name="Отправить смену статуса">
      <bpmn:incoming>person_Flow_1</bpmn:incoming>
      <bpmn:outgoing>person_Flow_2</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:endEvent id="person_end" name="Действие отправлено">
      <bpmn:incoming>person_Flow_2</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="person_Flow_0" sourceRef="person_start" targetRef="person_open" name="" />
    <bpmn:sequenceFlow id="person_Flow_1" sourceRef="person_open" targetRef="person_request" name="" />
    <bpmn:sequenceFlow id="person_Flow_2" sourceRef="person_request" targetRef="person_end" name="" />
  </bpmn:process>
  <bpmn:process id="backend_Process_backend" name="Tickets backend: объектные права, переход и commit" isExecutable="false">
    <bpmn:documentation>{"notes": ["Ручной переход показан отдельно от автоматического.", "Все сообщения backend отправляются после commit; доставка best effort через ejabberd.", "ticket.changed адресуется новому владельцу; ticket.moved прежнему. Потерю сообщения восстанавливает periodic reconciliation."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_st_request_assigned.json", "repository": "sharix-open-handlers-examples", "sha256": "d49e943a8806c3130acf09f1e93cf6b4e4a7d6f7428a5d18844a8f64ff619fe6"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_st_request_assigned.py", "repository": "sharix-open-handlers-examples", "sha256": "2be4d63c70b8469e541346aa3185bb29d04af1a87fb64fb1df118bde3ebe3c42"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_st_request_new.json", "repository": "sharix-open-handlers-examples", "sha256": "6b76b94236e6257f1f13dff9f41bb48c47352d5c512c9add0c5e53153c2dd6ff"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_st_request_new.py", "repository": "sharix-open-handlers-examples", "sha256": "f3cc74eccbc60431fff10e4989a4e499af85c7190b2e30cba8b097639cf1a23f"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "utils.py", "repository": "sharix-open-tickets", "sha256": "a5680205c6522e1d9a74d9d267fe9ee96faf6f06436b00877fc0a93d80234bf5"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "views/ticket_detail.py", "repository": "sharix-open-tickets", "sha256": "05d344b0fba14cf895400694d4a18f486c800fef08dd1acb43ea46909b9e7e59"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/views/handler_workflow.py", "repository": "sharix-open-tickets", "sha256": "f97c4b467a9a30749f5c4b86b39a833c430e57aaa1f030f70030d9b5c609d368"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/views/ticket.py", "repository": "sharix-open-tickets", "sha256": "b25a66fc52790f11ba7aca48527a4a5b6640a05ffa377ab58f562955f2695499"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/permissions.py", "repository": "sharix-open-tickets", "sha256": "a0e12d188313ae1e6a9b1502ec48c2dd7f76fffa78ecf50b5b1b33b040b290a1"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "urls.py", "repository": "sharix-open-tickets", "sha256": "c41101b32eb1132d63bf62d5bd96d344a79fe34946dc1635dc090921beb6e3c9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}]}</bpmn:documentation>
    <bpmn:laneSet id="backend_Lanes_backend">
      <bpmn:lane id="backend_Lane_api" name="Проверяемая операция смены статуса">
        <bpmn:flowNodeRef>backend_request</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_acl</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_allowed</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_commit</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_publish</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_done</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_reject</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_rejected</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="backend_request" name="Запрос из карточки/API">
      <bpmn:outgoing>backend_Flow_0</bpmn:outgoing>
      <bpmn:messageEventDefinition />
    </bpmn:startEvent>
    <bpmn:serviceTask id="backend_acl" name="Проверить права и доступный переход">
      <bpmn:incoming>backend_Flow_0</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_1</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="backend_allowed" name="Изменение разрешено?">
      <bpmn:incoming>backend_Flow_1</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_2</bpmn:outgoing>
      <bpmn:outgoing>backend_Flow_5</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="backend_commit" name="Зафиксировать IN_PROCESS и Event">
      <bpmn:incoming>backend_Flow_2</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_3</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sendTask id="backend_publish" name="После commit: два wakeup-события">
      <bpmn:incoming>backend_Flow_3</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_4</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:endEvent id="backend_done" name="Статус сохранён">
      <bpmn:incoming>backend_Flow_4</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:serviceTask id="backend_reject" name="Отказ: статус не изменён">
      <bpmn:incoming>backend_Flow_5</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_6</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="backend_rejected" name="Сообщить результат пользователю">
      <bpmn:incoming>backend_Flow_6</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="backend_Flow_0" sourceRef="backend_request" targetRef="backend_acl" name="" />
    <bpmn:sequenceFlow id="backend_Flow_1" sourceRef="backend_acl" targetRef="backend_allowed" name="" />
    <bpmn:sequenceFlow id="backend_Flow_2" sourceRef="backend_allowed" targetRef="backend_commit" name="Да" />
    <bpmn:sequenceFlow id="backend_Flow_3" sourceRef="backend_commit" targetRef="backend_publish" name="" />
    <bpmn:sequenceFlow id="backend_Flow_4" sourceRef="backend_publish" targetRef="backend_done" name="" />
    <bpmn:sequenceFlow id="backend_Flow_5" sourceRef="backend_allowed" targetRef="backend_reject" name="Нет" />
    <bpmn:sequenceFlow id="backend_Flow_6" sourceRef="backend_reject" targetRef="backend_rejected" name="" />
  </bpmn:process>
  <bpmn:collaboration id="Collaboration_st_assigned_external">
    <bpmn:participant id="person_Pool_person" name="Пользователь с доступом к Ticket и правом смены статуса" processRef="person_Process_person" />
    <bpmn:participant id="backend_Pool_backend" name="Tickets backend: объектные права, переход и commit" processRef="backend_Process_backend" />
    <bpmn:participant id="next_Participant" name="open_st_request_inprocess — новый владелец Ticket" />
    <bpmn:participant id="old_Participant" name="Прежний ASSIGNED: освободить локальную очередь" />
    <bpmn:messageFlow id="Message_st_assigned_external_0" sourceRef="person_request" targetRef="backend_request" name="Разрешённый интерфейс смены статуса" />
    <bpmn:messageFlow id="Message_st_assigned_external_1" sourceRef="backend_publish" targetRef="next_Participant" name="ticket.changed: новый статус IN_PROCESS" />
    <bpmn:messageFlow id="Message_st_assigned_external_2" sourceRef="backend_publish" targetRef="old_Participant" name="ticket.moved: прежний ASSIGNED → IN_PROCESS" />
  </bpmn:collaboration>
  <bpmndi:BPMNDiagram id="Diagram_st_assigned_external">
    <bpmndi:BPMNPlane id="Plane_st_assigned_external" bpmnElement="Collaboration_st_assigned_external">
      <bpmndi:BPMNShape id="person_DI_Pool_person" bpmnElement="person_Pool_person" isHorizontal="true">
        <dc:Bounds x="0.0" y="0.0" width="1100" height="200" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="person_DI_Lane_user" bpmnElement="person_Lane_user" isHorizontal="true">
        <dc:Bounds x="30.0" y="0.0" width="1070" height="200" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="person_DI_start" bpmnElement="person_start">
        <dc:Bounds x="142.0" y="82.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="person_DI_open" bpmnElement="person_open">
        <dc:Bounds x="345.0" y="65.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="person_DI_request" bpmnElement="person_request">
        <dc:Bounds x="625.0" y="65.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="person_DI_end" bpmnElement="person_end">
        <dc:Bounds x="922.0" y="82.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="person_DI_Flow_0" bpmnElement="person_Flow_0">
        <di:waypoint x="178.0" y="100.0" />
        <di:waypoint x="345.0" y="100.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="person_DI_Flow_1" bpmnElement="person_Flow_1">
        <di:waypoint x="495.0" y="100.0" />
        <di:waypoint x="625.0" y="100.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="person_DI_Flow_2" bpmnElement="person_Flow_2">
        <di:waypoint x="775.0" y="100.0" />
        <di:waypoint x="922.0" y="100.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="backend_DI_Pool_backend" bpmnElement="backend_Pool_backend" isHorizontal="true">
        <dc:Bounds x="0.0" y="270.0" width="1600" height="340" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_Lane_api" bpmnElement="backend_Lane_api" isHorizontal="true">
        <dc:Bounds x="30.0" y="270.0" width="1570" height="340" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_request" bpmnElement="backend_request">
        <dc:Bounds x="142.0" y="352.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_acl" bpmnElement="backend_acl">
        <dc:Bounds x="345.0" y="335.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_allowed" bpmnElement="backend_allowed">
        <dc:Bounds x="655.0" y="345.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_commit" bpmnElement="backend_commit">
        <dc:Bounds x="845.0" y="335.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_publish" bpmnElement="backend_publish">
        <dc:Bounds x="1105.0" y="335.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_done" bpmnElement="backend_done">
        <dc:Bounds x="1422.0" y="352.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_reject" bpmnElement="backend_reject">
        <dc:Bounds x="605.0" y="475.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_rejected" bpmnElement="backend_rejected">
        <dc:Bounds x="902.0" y="492.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="backend_DI_Flow_0" bpmnElement="backend_Flow_0">
        <di:waypoint x="178.0" y="370.0" />
        <di:waypoint x="345.0" y="370.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_1" bpmnElement="backend_Flow_1">
        <di:waypoint x="495.0" y="370.0" />
        <di:waypoint x="655.0" y="370.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_2" bpmnElement="backend_Flow_2">
        <di:waypoint x="705.0" y="370.0" />
        <di:waypoint x="845.0" y="370.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_3" bpmnElement="backend_Flow_3">
        <di:waypoint x="995.0" y="370.0" />
        <di:waypoint x="1105.0" y="370.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_4" bpmnElement="backend_Flow_4">
        <di:waypoint x="1255.0" y="370.0" />
        <di:waypoint x="1422.0" y="370.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_5" bpmnElement="backend_Flow_5">
        <di:waypoint x="680.0" y="395.0" />
        <di:waypoint x="680.0" y="475.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_6" bpmnElement="backend_Flow_6">
        <di:waypoint x="755.0" y="510.0" />
        <di:waypoint x="902.0" y="510.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="DI_next_Participant" bpmnElement="next_Participant" isHorizontal="true">
        <dc:Bounds x="0" y="680" width="760" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="DI_old_Participant" bpmnElement="old_Participant" isHorizontal="true">
        <dc:Bounds x="900" y="680" width="760" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="DI_Message_st_assigned_external_0" bpmnElement="Message_st_assigned_external_0">
        <di:waypoint x="700" y="135" />
        <di:waypoint x="700" y="230" />
        <di:waypoint x="160" y="230" />
        <di:waypoint x="160" y="352" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="270" y="205" width="260" height="42" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="DI_Message_st_assigned_external_1" bpmnElement="Message_st_assigned_external_1">
        <di:waypoint x="1180" y="405" />
        <di:waypoint x="1180" y="640" />
        <di:waypoint x="380" y="640" />
        <di:waypoint x="380" y="680" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="440" y="612" width="260" height="42" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="DI_Message_st_assigned_external_2" bpmnElement="Message_st_assigned_external_2">
        <di:waypoint x="1220" y="405" />
        <di:waypoint x="1220" y="620" />
        <di:waypoint x="1280" y="620" />
        <di:waypoint x="1280" y="680" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="1260" y="600" width="260" height="42" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

Пользователь открывает карточку Ticket и выбирает IN_PROCESS среди доступных переходов. Страница публикуется по маршруту tickets/ticket/<id>/; пользовательский API использует tickets/api/ticket/<id>/status. Общий префикс установки определяется её URL-конфигурацией. Наличие видимой ссылки или знание id не заменяют доступ к Ticket и право смены статуса.

Перед пользовательским переходом проверяются:

Создание Ticket само по себе не даёт права начать обработку. Change_ticket_status проверяет lifecycle, а объектные права обязан проверить вызывающий слой. Для связанного заказа действуют его доменные ограничения.

У автоматического обработчика другой вход: tickets/api/handler/ticket/<id>/transition, identity API-ключа, capability ticket.transition, рабочая область статуса и блокировка строки. Пользовательский и handler API нельзя считать взаимозаменяемыми по доступу.

После сохранения статуса и Event и завершения commit направляются два события:

Это не две команды повторно выполнить одно действие. Прежний обработчик получает сигнал о смене владельца, новый — повод получить свой scoped Ticket и начать собственную стадию. Передача идёт через ejabberd; failed delivery не откатывает сохранённый Ticket. При автоматической ветке дополнительно возможен прямой XMPP Ticket snapshot от send_to_handler. Runtime сопоставляет ревизии и объединяет повторные сигналы; постоянная гарантия exactly-once здесь не заявляется.

При недостатке прав или недоступном переходе статус не меняется. Обработчик не должен считать сам факт отправки пользовательского запроса началом следующей стадии. Прямое изменение БД не равно этой канонической операции с её lifecycle-событиями.

Уборка прежней очереди и восстановление доставки (BPMN)

Схема BPMN

Загрузка схемы…

Исходник схемы
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_st_assigned_cleanup" targetNamespace="urn:sharix:knowledge:handlers">
  <bpmn:process id="old_Process_old" name="Прежний open_st_request_assigned: уборка локальной очереди" isExecutable="false">
    <bpmn:documentation>{"notes": ["Ручной переход показан отдельно от автоматического.", "Все сообщения backend отправляются после commit; доставка best effort через ejabberd.", "ticket.changed адресуется новому владельцу; ticket.moved прежнему. Потерю сообщения восстанавливает periodic reconciliation."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_st_request_assigned.json", "repository": "sharix-open-handlers-examples", "sha256": "d49e943a8806c3130acf09f1e93cf6b4e4a7d6f7428a5d18844a8f64ff619fe6"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_st_request_assigned.py", "repository": "sharix-open-handlers-examples", "sha256": "2be4d63c70b8469e541346aa3185bb29d04af1a87fb64fb1df118bde3ebe3c42"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_st_request_new.json", "repository": "sharix-open-handlers-examples", "sha256": "6b76b94236e6257f1f13dff9f41bb48c47352d5c512c9add0c5e53153c2dd6ff"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_st_request_new.py", "repository": "sharix-open-handlers-examples", "sha256": "f3cc74eccbc60431fff10e4989a4e499af85c7190b2e30cba8b097639cf1a23f"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "utils.py", "repository": "sharix-open-tickets", "sha256": "a5680205c6522e1d9a74d9d267fe9ee96faf6f06436b00877fc0a93d80234bf5"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "views/ticket_detail.py", "repository": "sharix-open-tickets", "sha256": "05d344b0fba14cf895400694d4a18f486c800fef08dd1acb43ea46909b9e7e59"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/views/handler_workflow.py", "repository": "sharix-open-tickets", "sha256": "f97c4b467a9a30749f5c4b86b39a833c430e57aaa1f030f70030d9b5c609d368"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/views/ticket.py", "repository": "sharix-open-tickets", "sha256": "b25a66fc52790f11ba7aca48527a4a5b6640a05ffa377ab58f562955f2695499"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/permissions.py", "repository": "sharix-open-tickets", "sha256": "a0e12d188313ae1e6a9b1502ec48c2dd7f76fffa78ecf50b5b1b33b040b290a1"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "urls.py", "repository": "sharix-open-tickets", "sha256": "c41101b32eb1132d63bf62d5bd96d344a79fe34946dc1635dc090921beb6e3c9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}]}</bpmn:documentation>
    <bpmn:laneSet id="old_Lanes_old">
      <bpmn:lane id="old_Lane_queue" name="Событие или восстановление при потере доставки">
        <bpmn:flowNodeRef>old_moved</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_discard</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_end</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_periodic</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_timer</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_list</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_present</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_keep</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_next_check</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_query_error</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>old_retry</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="old_moved" name="Получено ticket.moved">
      <bpmn:outgoing>old_Flow_0</bpmn:outgoing>
      <bpmn:messageEventDefinition />
    </bpmn:startEvent>
    <bpmn:serviceTask id="old_discard" name="Запросить исключение локального Ticket">
      <bpmn:documentation>Если Ticket in-flight — pending discard до завершения worker; иначе удалить локальный снимок и комнату.</bpmn:documentation>
      <bpmn:incoming>old_Flow_0</bpmn:incoming>
      <bpmn:incoming>old_Flow_5</bpmn:incoming>
      <bpmn:outgoing>old_Flow_1</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="old_end" name="Исключён / ожидает завершения worker">
      <bpmn:incoming>old_Flow_1</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:startEvent id="old_periodic" name="Цикл periodic reconciliation">
      <bpmn:outgoing>old_Flow_2</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:intermediateCatchEvent id="old_timer" name="Срок INTERVAL_TIME_BD_REQ">
      <bpmn:incoming>old_Flow_2</bpmn:incoming>
      <bpmn:outgoing>old_Flow_3</bpmn:outgoing>
      <bpmn:timerEventDefinition>
        <bpmn:timeDate xsi:type="bpmn:tFormalExpression">next_reconciliation_at</bpmn:timeDate>
      </bpmn:timerEventDefinition>
    </bpmn:intermediateCatchEvent>
    <bpmn:serviceTask id="old_list" name="Scoped список ASSIGNED из API">
      <bpmn:incoming>old_Flow_3</bpmn:incoming>
      <bpmn:outgoing>old_Flow_4</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="old_present" name="Ticket ещё в списке?">
      <bpmn:incoming>old_Flow_4</bpmn:incoming>
      <bpmn:outgoing>old_Flow_5</bpmn:outgoing>
      <bpmn:outgoing>old_Flow_6</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="old_keep" name="Сохранить / обновить снимок">
      <bpmn:documentation>Изменившаяся authoritative revision делает Ticket ready; неизменившаяся сохраняет defer.</bpmn:documentation>
      <bpmn:incoming>old_Flow_6</bpmn:incoming>
      <bpmn:outgoing>old_Flow_7</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="old_next_check" name="Следующая плановая сверка">
      <bpmn:incoming>old_Flow_7</bpmn:incoming>
      <bpmn:incoming>old_Flow_9</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:boundaryEvent id="old_query_error" name="API недоступен" attachedToRef="old_list" cancelActivity="true">
      <bpmn:outgoing>old_Flow_8</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:serviceTask id="old_retry" name="Сохранить старый снимок, повторить">
      <bpmn:incoming>old_Flow_8</bpmn:incoming>
      <bpmn:outgoing>old_Flow_9</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sequenceFlow id="old_Flow_0" sourceRef="old_moved" targetRef="old_discard" name="" />
    <bpmn:sequenceFlow id="old_Flow_1" sourceRef="old_discard" targetRef="old_end" name="" />
    <bpmn:sequenceFlow id="old_Flow_2" sourceRef="old_periodic" targetRef="old_timer" name="" />
    <bpmn:sequenceFlow id="old_Flow_3" sourceRef="old_timer" targetRef="old_list" name="" />
    <bpmn:sequenceFlow id="old_Flow_4" sourceRef="old_list" targetRef="old_present" name="" />
    <bpmn:sequenceFlow id="old_Flow_5" sourceRef="old_present" targetRef="old_discard" name="Нет" />
    <bpmn:sequenceFlow id="old_Flow_6" sourceRef="old_present" targetRef="old_keep" name="Да" />
    <bpmn:sequenceFlow id="old_Flow_7" sourceRef="old_keep" targetRef="old_next_check" name="" />
    <bpmn:sequenceFlow id="old_Flow_8" sourceRef="old_query_error" targetRef="old_retry" name="" />
    <bpmn:sequenceFlow id="old_Flow_9" sourceRef="old_retry" targetRef="old_next_check" name="" />
  </bpmn:process>
  <bpmn:collaboration id="Collaboration_st_assigned_cleanup">
    <bpmn:participant id="old_Pool_old" name="Прежний open_st_request_assigned: уборка локальной очереди" processRef="old_Process_old" />
  </bpmn:collaboration>
  <bpmndi:BPMNDiagram id="Diagram_st_assigned_cleanup">
    <bpmndi:BPMNPlane id="Plane_st_assigned_cleanup" bpmnElement="Collaboration_st_assigned_cleanup">
      <bpmndi:BPMNShape id="old_DI_Pool_old" bpmnElement="old_Pool_old" isHorizontal="true">
        <dc:Bounds x="0.0" y="0.0" width="1600" height="560" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_Lane_queue" bpmnElement="old_Lane_queue" isHorizontal="true">
        <dc:Bounds x="30.0" y="0.0" width="1570" height="560" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_moved" bpmnElement="old_moved">
        <dc:Bounds x="142.0" y="82.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_discard" bpmnElement="old_discard">
        <dc:Bounds x="345.0" y="65.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_end" bpmnElement="old_end">
        <dc:Bounds x="662.0" y="82.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_periodic" bpmnElement="old_periodic">
        <dc:Bounds x="142.0" y="282.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_timer" bpmnElement="old_timer">
        <dc:Bounds x="402.0" y="282.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_list" bpmnElement="old_list">
        <dc:Bounds x="605.0" y="265.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_present" bpmnElement="old_present">
        <dc:Bounds x="895.0" y="275.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_keep" bpmnElement="old_keep">
        <dc:Bounds x="1105.0" y="265.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_next_check" bpmnElement="old_next_check">
        <dc:Bounds x="1422.0" y="282.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_query_error" bpmnElement="old_query_error">
        <dc:Bounds x="712.0" y="317.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="old_DI_retry" bpmnElement="old_retry">
        <dc:Bounds x="845.0" y="425.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="old_DI_Flow_0" bpmnElement="old_Flow_0">
        <di:waypoint x="178.0" y="100.0" />
        <di:waypoint x="345.0" y="100.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_1" bpmnElement="old_Flow_1">
        <di:waypoint x="495.0" y="100.0" />
        <di:waypoint x="662.0" y="100.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_2" bpmnElement="old_Flow_2">
        <di:waypoint x="178.0" y="300.0" />
        <di:waypoint x="402.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_3" bpmnElement="old_Flow_3">
        <di:waypoint x="438.0" y="300.0" />
        <di:waypoint x="605.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_4" bpmnElement="old_Flow_4">
        <di:waypoint x="755.0" y="300.0" />
        <di:waypoint x="895.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_5" bpmnElement="old_Flow_5">
        <di:waypoint x="945.0" y="300.0" />
        <di:waypoint x="645.0" y="300.0" />
        <di:waypoint x="645.0" y="100.0" />
        <di:waypoint x="345.0" y="100.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_6" bpmnElement="old_Flow_6">
        <di:waypoint x="945.0" y="300.0" />
        <di:waypoint x="1105.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_7" bpmnElement="old_Flow_7">
        <di:waypoint x="1255.0" y="300.0" />
        <di:waypoint x="1422.0" y="300.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_8" bpmnElement="old_Flow_8">
        <di:waypoint x="748.0" y="335.0" />
        <di:waypoint x="796.5" y="335.0" />
        <di:waypoint x="796.5" y="460.0" />
        <di:waypoint x="845.0" y="460.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="old_DI_Flow_9" bpmnElement="old_Flow_9">
        <di:waypoint x="995.0" y="460.0" />
        <di:waypoint x="1208.5" y="460.0" />
        <di:waypoint x="1208.5" y="300.0" />
        <di:waypoint x="1422.0" y="300.0" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

Уборка при ticket.moved:

  1. XMPP-обработка ставит запрос discard без синхронного API GET.
  2. Для in-flight Ticket удаление откладывается до завершения worker.
  3. Для свободного Ticket локальный снимок исключается сразу, запрашивается удаление комнаты.

Успешная явная передача текущего handler сохраняет комнату. Очистка локальной очереди не удаляет Ticket из backend.

Периодическая scoped сверка по INTERVAL_TIME_BD_REQ:

Недоступность API не является подтверждённым удалением заявки.

Отсрочки, причины ожидания, coalescing событий и локальная очередь живут в памяти процесса. После restart authoritative-состав восстанавливается из backend; прежний deadline не является долговечным SLA-обязательством. deferred_until и next_reconciliation_at в BPMN — символические значения сроков, не новые env-ключи и не фиксированное число секунд. Служебные startup/stop-пути общего runtime не развёрнуты здесь в отдельный бизнес-процесс.

Диагностика

Источники и актуализация

Ниже закреплены изученные версии. SHA-256 файлов и параметры генерации также сохранены в metadata страницы и documentation внутри BPMN. Алгоритм берётся из Blockly и его точно совпадающего Python; роли, commit-события и восстановление — из runtime, view/API/ACL и signals. Изменение этих источников требует повторного сопоставления, а не механической смены хешей.

Связанные материалы