Инструменты пользователя

Инструменты сайта


sharixopen:knowledge:scenarios:st_request_assigned

Это старая версия документа!


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

Область: ShariX Open. Обработчик: open_st_request_assigned, тип ST_REQUEST (1), рабочий статус ASSIGNED. Описана опубликованная встроенная реализация и проверенные внешние контракты на 28.10.2026. Python побайтово сверен с каноническим render его Blockly workspace. На конкретном сервере дополнительно имеют значение выбранная локальная версия, настройки и готовность runtime.

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

Обработчик обслуживает уже назначенную стадию заявки. Он не выбирает сотрудника, не заполняет assigned_to, не проверяет наличие назначенного человека и сам не выполняет содержание обращения. При ручном режиме он освобождает worker и ждёт дальнейшего действия; при автоматическом — запрашивает следующий статус и передаёт Ticket следующему обработчику.

Статус 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 записывается support_execution и назначается defer через ST_REQUEST_ASSIGNED_RECHECK_SECONDS. Текущий worker освобождается. Срок делает Ticket пригодным для повторной постановки в ready FIFO; запуск зависит также от свободного worker и готовности XMPP. Новая подтверждённая ревизия снимка может снять defer раньше. Одинаковое повторное событие само по себе не является новым решением и не требует повторного бизнес-действия.

При включённом STREQ_AUTOACCEPT выполняется узкая операция ticket.transition в IN_PROCESS. Успех API предшествует send_to_handler в open_st_request_inprocess. Затем текущая очередь освобождается с 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 и право смены статуса.

View проверяет объектный доступ и user_can_change_ticket_status. Предикат допускает staff/superuser, участника группы списка тикета, назначенного пользователя и, в общем контракте Tickets, provider связанного Order. Сам факт создания Ticket не даёт права принять его или начать обработку. Затем change_ticket_status проверяет допустимость перехода; эта общая функция сама не проверяет объектные права — это обязанность вызывающего слоя.

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

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

  • ticket.changed с новым статусом IN_PROCESS направляется в open_st_request_inprocess;
  • ticket.moved с прежним ASSIGNED и новым статусом направляется в open_st_request_assigned, чтобы прежняя очередь исключила свой снимок.

Это не две команды повторно выполнить одно действие. Прежний обработчик получает сигнал о смене владельца, новый — повод получить свой 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 текущая XMPP-обработка ставит запрос на discard без синхронного API GET. Если Ticket сейчас выполняется, исключение откладывается до завершения worker; параллельный второй проход для него не создаётся. Если он не in-flight, runtime сразу убирает локальный снимок и запрашивает удаление комнаты. Конкретная очистка комнаты зависит от ветки: успешная явная передача текущего handler сохраняет её.

Независимо от доставки сообщений очередь периодически получает scoped список по INTERVAL_TIME_BD_REQ. Ticket, отсутствующий в успешно полученном списке ASSIGNED, исключается сразу либо после in-flight прохода. При новой ревизии сохраняется свежий снимок и снимается defer; неизменившийся снимок не обнуляет ожидание без причины. Если API недоступен, неизвестность не трактуется как удаление Ticket: локальный снимок сохраняется, ошибка логируется, следующая сверка назначается обычным циклом.

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

Диагностика

  • Какой статус и ревизия Ticket сохранены в backend; выбран ли именно этот built-in или локальная версия обработчика.
  • Какое значение STREQ_AUTOACCEPT было прочитано при старте; какое значение ST_REQUEST_ASSIGNED_RECHECK_SECONDS использует текущий runtime.
  • Есть ли support_execution, активный defer, ready FIFO, свободный worker и готовое XMPP. Эти признаки описывают разные стадии ожидания.
  • Не ожидается ли удаление старого снимка после ticket.moved или in-flight прохода; завершалась ли последняя scoped сверка успешно.
  • Не завершился ли API-переход раньше ошибки XMPP. Проверять фактический backend-статус перед повтором действия, а не выводить его из сообщения об ошибке отправки.
  • Для ручного перехода — доступ к Ticket, объектные права и доступный следующий статус. Авторство Ticket само по себе недостаточно.

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

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

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

sharixopen/knowledge/scenarios/st_request_assigned.1793211589.txt.gz · Последнее изменение: — sx_knowledge_api_open

© 2022 ShariX