Files
documents/GEGI/portfolio/tasks description/Task #80238 [&] CourseKey Integration Requests Based on Queue Очередь отправки - GEGI Monolith - Redmine https __redmine.gegi.co_issues_80238.html
mguschin 050d0a4c49 Init.
2026-02-02 19:13:26 +03:00

1232 lines
86 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Task #80238: [&amp;] CourseKey Integration: Requests Based on Queue: Очередь отправки - GEGI Monolith - Redmine</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Redmine" />
<meta name="keywords" content="issue,bug,tracker" />
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="dOghxavHSzPCWY5EhJm2Q5+f0lFNFjbLcR1s2wgNUEZ8wxnhaaaheXXur72EOryKTPWMW2AtV6hpB4ucbYJtmg==" />
<link rel='shortcut icon' href='/favicon.ico?1469436615' />
<link rel="stylesheet" media="all" href="/stylesheets/jquery/jquery-ui-1.13.2.css?1685504110" />
<link rel="stylesheet" media="all" href="/stylesheets/tribute-5.1.3.css?1617962912" />
<link rel="stylesheet" media="all" href="/themes/alternate/stylesheets/application.css?1580116318" />
<link rel="stylesheet" media="all" href="/stylesheets/responsive.css?1704618418" />
<script src="/javascripts/jquery-3.6.1-ui-1.13.2-ujs-6.1.7.6.js?1704618418"></script>
<script src="/javascripts/tribute-5.1.3.min.js?1617962912"></script>
<script src="/javascripts/tablesort-5.2.1.min.js?1617962912"></script>
<script src="/javascripts/tablesort-5.2.1.number.min.js?1617962912"></script>
<script src="/javascripts/application.js?1704618418"></script>
<script src="/javascripts/responsive.js?1704618418"></script>
<script>
//<![CDATA[
$(window).on('load', function(){ warnLeavingUnsaved('The current page contains unsaved text that will be lost if you leave this page.'); });
//]]>
</script>
<script>
//<![CDATA[
rm = window.rm || {};rm.AutoComplete = rm.AutoComplete || {};rm.AutoComplete.dataSources = JSON.parse('{"issues":"/issues/auto_complete?project_id=gegi-llc-gegi-tasks\u0026q=","wiki_pages":"/wiki_pages/auto_complete?project_id=gegi-llc-gegi-tasks\u0026q="}');
//]]>
</script>
<!-- page specific tags -->
<script src="/javascripts/jstoolbar/jstoolbar.js?1617962912"></script><script src="/javascripts/jstoolbar/textile.js?1685504110"></script><script src="/javascripts/jstoolbar/lang/jstoolbar-en.js?1617962912"></script><script>
//<![CDATA[
var wikiImageMimeTypes = ["image/gif","image/jpeg","image/png","image/tiff","image/webp","image/x-ms-bmp"];var userHlLanguages = ["css","diff","html","javascript","php","shell","sql","xml","yaml"];
//]]>
</script><link rel="stylesheet" media="screen" href="/stylesheets/jstoolbar.css?1685504110" /><script>
//<![CDATA[
var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: 0, showOn: 'button', buttonImageOnly: true, buttonImage: '/images/calendar.png?1469436614', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true, changeMonth: true, changeYear: true, beforeShow: beforeShowDatePicker};
//]]>
</script> <script src="/javascripts/attachments.js?1685504110"></script>
<link rel="alternate" type="application/atom+xml" title="GEGI Monolith - Task #80238: [&amp;] CourseKey Integration: Requests Based on Queue: Очередь отправки" href="https://redmine.gegi.co/issues/80238.atom?key=9a0e762bc0de6fd11e6a128b812884226e58f668" />
<script src="/javascripts/context_menu.js?1685504110"></script><link rel="stylesheet" media="screen" href="/stylesheets/context_menu.css?1685504110" /></head>
<body class="theme-Alternate project-gegi-llc-gegi-tasks has-main-menu controller-issues action-show avatars-on textarea-monospace">
<div id="wrapper">
<div class="flyout-menu js-flyout-menu">
<div class="flyout-menu__search">
<form action="/projects/gegi-llc-gegi-tasks/search" accept-charset="UTF-8" name="form-3ef9ccb1" method="get"><input name="utf8" type="hidden" value="&#x2713;" autocomplete="off" />
<input type="hidden" name="issues" value="1" autocomplete="off" />
<label class="search-magnifier search-magnifier--flyout" for="flyout-search">&#9906;</label>
<input type="text" name="q" id="flyout-search" class="small js-search-input" placeholder="Search" />
</form> </div>
<div class="flyout-menu__avatar ">
<a href="/users/109"><img alt="" title="Mikhail Guschin" class="gravatar" srcset="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=160&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=80&amp;default=identicon" /></a>
<a class="user active" href="/users/109">mguschin</a>
</div>
<h3>Project</h3>
<span class="js-project-menu"></span>
<h3>General</h3>
<span class="js-general-menu"></span>
<span class="js-sidebar flyout-menu__sidebar"></span>
<h3>Profile</h3>
<span class="js-profile-menu"></span>
</div>
<div id="top-menu">
<div id="account">
<ul><li><a class="my-account" href="/my/account">My account</a></li><li><a class="logout" rel="nofollow" data-method="post" href="/logout">Sign out</a></li></ul> </div>
<div id="loggedas">Logged in as <a class="user active" href="/users/109">mguschin</a></div>
<ul><li><a class="home" href="/">Home</a></li><li><a class="my-page" href="/my/page">My page</a></li><li><a class="projects" href="/projects">Projects</a></li><li><a target="_blank" rel="noopener" class="help" href="https://www.redmine.org/guide">Help</a></li></ul></div>
<div id="header">
<a href="#" class="mobile-toggle-button js-flyout-menu-toggle-button"></a>
<div id="quick-search">
<form action="/projects/gegi-llc-gegi-tasks/search" accept-charset="UTF-8" name="form-d9df5db5" method="get"><input name="utf8" type="hidden" value="&#x2713;" autocomplete="off" />
<input type="hidden" name="scope" value="subprojects" autocomplete="off" />
<input type="hidden" name="issues" value="1" autocomplete="off" />
<label for='q'>
<a accesskey="4" href="/projects/gegi-llc-gegi-tasks/search?scope=subprojects">Search</a>:
</label>
<input type="text" name="q" id="q" size="20" class="small" accesskey="f" data-auto-complete="true" />
</form> <div id="project-jump" class="drdn"><span class="drdn-trigger">GEGI Monolith</span><div class="drdn-content"><div class="quick-search"><input type="text" name="q" id="projects-quick-search" value="" class="autocomplete" data-automcomplete-url="/projects/autocomplete.js?jump=issues" autocomplete="off" /></div><div class="drdn-items projects selection"><strong>Bookmarks</strong><a title="GEGI SIS" href="/projects/gegi?jump=issues"><span style="padding-left:0px;">GEGI SIS</span></a><a title="GEGI Monolith" class="selected" href="/projects/gegi-llc-gegi-tasks?jump=issues"><span style="padding-left:16px;">GEGI Monolith</span></a><a title="GEGI Services" href="/projects/gegi-services?jump=issues"><span style="padding-left:16px;">GEGI Services</span></a><strong>Recently used</strong><a title="User Stories" href="/projects/gegi-llc-user-stories?jump=issues"><span style="padding-left:0px;">User Stories</span></a><a title="GEGI LLC" href="/projects/gegi-llc?jump=issues"><span style="padding-left:0px;">GEGI LLC</span></a><a title="Daily Reports" href="/projects/reports?jump=issues"><span style="padding-left:0px;">Daily Reports</span></a><strong>All Projects</strong><a title="GEGI LLC" href="/projects/gegi-llc?jump=issues"><span style="padding-left:0px;">GEGI LLC</span></a><a title="Daily Reports" href="/projects/reports?jump=issues"><span style="padding-left:16px;">Daily Reports</span></a><a title="GEGI SIS" href="/projects/gegi?jump=issues"><span style="padding-left:16px;">GEGI SIS</span></a><a title="GEGI Monolith" class="selected" href="/projects/gegi-llc-gegi-tasks?jump=issues"><span style="padding-left:32px;">GEGI Monolith</span></a><a title="[Old] GEGI Monolith" href="/projects/gama-estimator?jump=issues"><span style="padding-left:48px;">[Old] GEGI Monolith</span></a><a title="GEGI Services" href="/projects/gegi-services?jump=issues"><span style="padding-left:32px;">GEGI Services</span></a><a title="User Docs &amp; Rollout" href="/projects/gegi-documentation?jump=issues"><span style="padding-left:32px;">User Docs &amp; Rollout</span></a><a title="GEGI Website" href="/projects/gegi-website?jump=issues"><span style="padding-left:16px;">GEGI Website</span></a><a title="Customer Care Team" href="/projects/customer-care?jump=issues"><span style="padding-left:16px;">Customer Care Team</span></a><a title="Data Analysts Team" href="/projects/data-analysts?jump=issues"><span style="padding-left:16px;">Data Analysts Team</span></a><a title="Infrastructure Team" href="/projects/gegi-llc-server-tasks?jump=issues"><span style="padding-left:16px;">Infrastructure Team</span></a><a title="User Stories" href="/projects/gegi-llc-user-stories?jump=issues"><span style="padding-left:16px;">User Stories</span></a></div><div class="drdn-items all-projects selection"><a href="/projects?jump=issues">All Projects</a></div></div></div>
</div>
<h1><span class="breadcrumbs"><a class="root" href="/projects/gegi-llc?jump=issues">GEGI LLC</a><span class="separator"> &raquo; </span><a class="ancestor" href="/projects/gegi?jump=issues">GEGI SIS</a><span class="separator"> &raquo; </span></span><span class="current-project">GEGI Monolith</span></h1>
<div id="main-menu" class="tabs">
<ul><li><a class="overview" href="/projects/gegi-llc-gegi-tasks">Overview</a></li><li><a class="activity" href="/projects/gegi-llc-gegi-tasks/activity">Activity</a></li><li><a class="roadmap" href="/projects/gegi-llc-gegi-tasks/roadmap">Roadmap</a></li><li><a class="issues selected" href="/projects/gegi-llc-gegi-tasks/issues">Issues</a></li><li><a accesskey="7" class="new-issue" href="/projects/gegi-llc-gegi-tasks/issues/new">New issue</a></li><li><a class="time-entries" href="/projects/gegi-llc-gegi-tasks/time_entries">Spent time</a></li><li><a class="calendar" href="/projects/gegi-llc-gegi-tasks/issues/calendar">Calendar</a></li><li><a class="wiki" href="/projects/gegi-llc-gegi-tasks/wiki">Wiki</a></li><li><a class="repository" href="/projects/gegi-llc-gegi-tasks/repository">Repository</a></li></ul>
<div class="tabs-buttons" style="display:none;">
<button class="tab-left" onclick="moveTabLeft(this); return false;"></button>
<button class="tab-right" onclick="moveTabRight(this); return false;"></button>
</div>
</div>
</div>
<div id="main" class="">
<div id="sidebar">
<h3>My custom queries</h3>
<ul class="queries"><li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=807">Daily Report Template</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=805">Daily Reports My</a></li>
<li><a class="query selected" href="/projects/gegi-llc-gegi-tasks/issues?query_id=804">Open Assignee Me</a><a class="icon-only icon-clear-query" title="Clear" href="/issues/80238?project_id=gegi-llc-gegi-tasks&amp;set_filter=1&amp;sort=">Clear</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=826">Open Assignee Me [E]</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=702">Story Done Last Month</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=514">Team Tasks</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=812">Tech Support</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=803">Tech Support CK</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=802">Tech Support FA</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=825">Tech Support FA/CK (Created more then 60 days ago)</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=544">[&amp;]</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=504">[&amp;] AND [-&amp;]</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=539">[-&amp;]</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=597">[-&amp;] rc</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=604">[-&amp;] trunk</a></li></ul>
<h3>Custom queries</h3>
<ul class="queries"><li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=691">My Issues</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=442">My Issues: By Priority</a></li>
<li><a class="query" href="/projects/gegi-llc-gegi-tasks/issues?query_id=106">My Issues: By Status</a></li></ul>
</div>
<div id="content">
<div class="contextual">
<a onclick="showAndScrollTo(&quot;update&quot;, &quot;issue_notes&quot;); return false;" class="icon icon-edit" accesskey="e" href="/issues/80238/edit">Edit</a>
<a class="icon icon-time-add" href="/issues/80238/time_entries/new">Log time</a>
<a class="issue-80238-watcher icon icon-fav-off" data-remote="true" rel="nofollow" data-method="post" href="/watchers/watch?object_id=80238&amp;object_type=issue">Watch</a>
<a class="icon icon-copy" href="/projects/gegi-llc-gegi-tasks/issues/80238/copy">Copy</a>
<span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items">
<a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238">Copy link</a>
</div></div></span></div>
<h2 class="inline-flex">Task #80238</h2>
<span class="badge badge-status-open">open</span>
<div class="issue tracker-1 status-2 priority-4 priority-default child parent created-by-me details">
<div class="gravatar-with-child">
<img alt="" title="Author: Mikhail Guschin" class="gravatar" srcset="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=100&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=50&amp;default=identicon" />
<img alt="" title="Assignee: Maksim Fomin" class="gravatar gravatar-child" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=44&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=22&amp;default=identicon" />
</div>
<div class="subject">
<div><p><a class="issue tracker-1 status-2 priority-4 priority-default parent" href="/issues/79968">Task #79968</a>: [&amp;] (Tech Story) CourseKey Integration: Requests Based on Queue</p><div><h3>[&amp;] CourseKey Integration: Requests Based on Queue: Очередь отправки</h3></div></div>
</div>
<p class="author">
Added by <a class="user active" href="/users/109">Mikhail Guschin</a> <a title="02/16/2024 15:40" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago.
Updated <a title="02/26/2024 16:37" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-26">about 19 hours</a> ago.
</p>
<div class="attributes">
<div class="splitcontent"><div class="splitcontentleft"><div class="status attribute"><div class="label">Status:</div><div class="value">In Progress</div></div><div class="priority attribute"><div class="label">Priority:</div><div class="value">Normal</div></div><div class="assigned-to attribute"><div class="label">Assignee:</div><div class="value"><a class="user active" href="/users/246">Maksim Fomin</a></div></div><div class="fixed-version attribute"><div class="label">Target version:</div><div class="value"><a href="/versions/927">GEGI SIS - 4.x.x Dev</a></div></div></div><div class="splitcontentleft"><div class="start-date attribute"><div class="label">Start date:</div><div class="value"></div></div><div class="due-date attribute"><div class="label">Due date:</div><div class="value"></div></div><div class="estimated-hours attribute"><div class="label">Estimated time:</div><div class="value">3.00 h (Total: 40.75 h)</div></div><div class="spent-time attribute"><div class="label">Spent time:</div><div class="value"> (Total: <a href="/time_entries?issue_id=~80238">25.25 h</a>)</div></div></div></div>
<div class="splitcontent"><div class="splitcontentleft"><div class="list_cf cf_21 attribute"><div class="label"><span>Release Notes</span>:</div><div class="value"></div></div></div><div class="splitcontentleft"><div class="list_cf cf_24 attribute"><div class="label"><span>Tech Support</span>:</div><div class="value">No</div></div></div></div>
</div>
<hr />
<div class="description">
<div class="contextual">
<a class="icon icon-comment" data-remote="true" rel="nofollow" data-method="post" href="/issues/80238/quoted">Quote</a>
</div>
<p><strong>Description</strong></p>
<div class="wiki">
Доработать очередь отправки (таблица <code>coursekey_requests.sql</code>):
<ol>
<li>Добавить поле bool для хранения факта отправки. Добавить Индекс.</li>
<li>Добавить поле для хранения datetime отправки. </li>
<li>Добавить поля для поддержки цепочек (chain): номер цепочки, порядковый номер запроса в цепочке.</li>
<li>Поменять типы json полей на json (например RequestParams).</li>
</ol>
<hr />
Добавить класс <code>GEGI\CourseKey\Requests\Request</code> для работы с coursekey_requests.sql.
<ol>
<li>Наследовать его от CollectionItem, т.к. коллекция нужна будет нам чтобы массово сохранять ответы в БД.</li>
<li>Свойства из БД.</li>
</ol>
<hr />
Добавить фоновый скрипт <code>send-coursekey-requests.php</code>:
<ol>
<li>Запускается раз в N минут по настройке <a href="https://dev.app.gegi.co/admin/school-settings/edit?name=System_CourseKeySyncPeriod" class="external">Period of Synchronization, Minutes</a>. <br />Работает только если включена <a href="https://dev.app.gegi.co/admin/school-settings/edit?name=System_CourseKeyEnableSync" class="external">Enable CourseKey Synchronization</a>.</li>
<li>Выбирает все не отправленные записи coursekey_requests.sql в коллекцию:</li>
<li>сортирует их по номеру цепочки и по порядковому номеру запроса в цепочке.</li>
<li>ограничивает количество не большими порциями (важно выбирать полные цепочки), т.к. отправка частая.</li>
<li>Отправляет их один за другим и фиксирует ответы в объектах. Затем массово сохраняет их в БД.</li>
<li>Если запрос в цепочке выполнился с ошибкой:
<ol>
<li>Фиксирует ошибку.</li>
<li>Решает остановить ли цепочку. Нужен гибкий способ настраивать такие решения (будет отдельный класс <code>ChainSendPolicy</code>). Если остановить, то останавливает и переходит к следующей цепочке. Если можно продолжать, то продолжает.</li>
</ol>
</li>
<li>Для каждого запроса добавляет фоновую задачу (dispatcher task) пост-обработки. Так делаем, потому что бывают "тяжелые" алгоритмы (например пересчет SAP).
<ol>
<li>Фиксирует в отдельном поле Id такой задачи и статус. Таск пост-обработчик после выполнения меняет этот статус.</li>
</ol></li>
</ol>
<hr />
Добавить класс <code>GEGI\CourseKey\Requests\Chain</code> для работы с цепочками:
<ol>
<li>Содержит массив запросов <code>GEGI\CourseKey\Requests\Request</code> с порядковыми номерами (можно использовать индексы массива пронумерованные от 1).</li>
<li>Содержит объект <code>GEGI\CourseKey\Requests\ChainSendPolicy</code> которая объясняет сценарий действий если при отправке в цепочке есть ошибка.</li>
</ol>
<hr />
Добавить класс <code>GEGI\CourseKey\Requests\ChainSendPolicy</code> для описания политик обработки ошибок:
<ol>
<li>Содержит имя.</li>
<li>Содержит метод, который на переданный код ответа ({200, ОК}, {400, User Exists} и др.) возвращает сигнал, что делать: продолжить запросы в цепочке, остановить, повторить, отменить сделанные запросы и др.</li>
</ol>
<a name="Results"></a>
<h2 >Results<a href="#Results" class="wiki-anchor">&para;</a></h2>
Разработка ведётся в ветке: <a href="https://github.com/gegillc/gegi-monolith/tree/feature/79114-coursekey-integration-requests-based-on-queue" class="external">feature/79114-coursekey-integration-requests-based-on-queue</a>.
<ol>
<li>Доработал очередь отправки. Добавлены новые колонки.</li>
<li>Добавил коллекции для работы с таблицей.</li>
<li>Добавил фоновый скрипт.</li>
<li>Добавил класс Chain - который работает с цепочкой.</li>
<li>Добавил прототип класса ChainSendPolicy.</li>
</ol>
</div>
</div>
<hr />
<p><strong>Files</strong></p>
<div class="attachments">
<div class="contextual">
<a title="Edit attached files" class="icon-only icon-edit" href="/attachments/issues/80238/edit">Edit attached files</a>
<a title="Download all files" class="icon-only icon-download" href="/attachments/issues/80238/download">Download all files</a>
</div>
<table>
<tr>
<td>
<a class="icon icon-attachment" href="/attachments/36342">clipboard-202402231857-4s31f.png</a> <span class="size">(268 KB)</span>
<a class="icon-only icon-download" title="Download" href="/attachments/download/36342/clipboard-202402231857-4s31f.png">clipboard-202402231857-4s31f.png</a> </td>
<td>Классы</td>
<td>
<span class="author">Maksim Fomin, 02/23/2024 17:57</span>
</td>
<td>
<a data-confirm="Are you sure?" class="delete icon-only icon-del" title="Delete" rel="nofollow" data-method="delete" href="/attachments/36342">Delete</a>
</td>
</tr>
<tr>
<td>
<a class="icon icon-attachment" href="/attachments/36357">clipboard-202402261726-up7rv.png</a> <span class="size">(327 KB)</span>
<a class="icon-only icon-download" title="Download" href="/attachments/download/36357/clipboard-202402261726-up7rv.png">clipboard-202402261726-up7rv.png</a> </td>
<td>2 версия класов</td>
<td>
<span class="author">Maksim Fomin, 02/26/2024 16:26</span>
</td>
<td>
<a data-confirm="Are you sure?" class="delete icon-only icon-del" title="Delete" rel="nofollow" data-method="delete" href="/attachments/36357">Delete</a>
</td>
</tr>
</table>
<div class="thumbnails">
<div><a title="clipboard-202402231857-4s31f.png" href="/attachments/36342"><img srcset="/attachments/thumbnail/36342/800 2x" style="max-width: 400px; max-height: 400px;" loading="lazy" src="/attachments/thumbnail/36342/800" /></a></div>
<div><a title="clipboard-202402261726-up7rv.png" href="/attachments/36357"><img srcset="/attachments/thumbnail/36357/800 2x" style="max-width: 400px; max-height: 400px;" loading="lazy" src="/attachments/thumbnail/36357/800" /></a></div>
</div>
</div>
<hr />
<div id="issue_tree">
<div class="contextual">
<a href="/projects/gegi-llc-gegi-tasks/issues/new?back_url=%2Fissues%2F80238&amp;issue%5Bparent_issue_id%5D=80238&amp;issue%5Btracker_id%5D=1">Add</a>
</div>
<p>
<strong>Subtasks</strong>
<span class="issues-stat"><span class="badge badge-issues-count"><a href="/issues?parent_id=~80238&amp;set_filter=true&amp;status_id=%2A">5</a></span> (<span class="open"><a href="/issues?parent_id=~80238&amp;set_filter=true&amp;status_id=o">5 open</a></span> &#8212; <span class="closed">0 closed</span>)</span>
</p>
<form data-cm-url="/issues/context_menu" action="/issues/80238" accept-charset="UTF-8" name="form-88f14a42" method="post"><input name="utf8" type="hidden" value="&#x2713;" autocomplete="off" /><input type="hidden" name="authenticity_token" value="AFCx91ER25J2TXs44TrTyE790GiYXdSpqb5D2mEfu3QIe4nTk3Ax2MH6WsHhmdkBnZeOYrVmtcqxpKSdBJCGqA==" autocomplete="off" />
<table class="list issues odd-even"><tr class="issue issue-80245 hascontextmenu issue tracker-1 status-10 priority-4 priority-default child assigned-to-me"><td class="checkbox"><input type="checkbox" name="ids[]" value="80245" /></td><td class="subject"><a class="issue tracker-1 status-10 priority-4 priority-default child assigned-to-me" href="/issues/80245">Task #80245</a>: CourseKey Integration: Requests Based on Queue: Очередь отправки: Доработать очередь отправки</td><td class="status">Testing</td><td class="assigned_to"><a class="user active" href="/users/109">Mikhail Guschin</a></td><td class="start_date"></td><td class="due_date"></td><td class="done_ratio"></td><td class="buttons"><a data-confirm="Are you sure?" title="Delete link to subtask" class="icon-only icon-link-break" rel="nofollow" data-method="put" href="/issues/80245?back_url=%2Fissues%2F80238&amp;issue%5Bparent_issue_id%5D=&amp;no_flash=1">Delete link to subtask</a><a title="Actions" class="icon-only icon-actions js-contextmenu" href="#">Actions</a></td></tr><tr class="issue issue-80246 hascontextmenu issue tracker-1 status-10 priority-4 priority-default child assigned-to-me"><td class="checkbox"><input type="checkbox" name="ids[]" value="80246" /></td><td class="subject"><a class="issue tracker-1 status-10 priority-4 priority-default child assigned-to-me" href="/issues/80246">Task #80246</a>: CourseKey Integration: Requests Based on Queue: Очередь отправки: Добавить коллекцию Request</td><td class="status">Testing</td><td class="assigned_to"><a class="user active" href="/users/109">Mikhail Guschin</a></td><td class="start_date"></td><td class="due_date"></td><td class="done_ratio"></td><td class="buttons"><a data-confirm="Are you sure?" title="Delete link to subtask" class="icon-only icon-link-break" rel="nofollow" data-method="put" href="/issues/80246?back_url=%2Fissues%2F80238&amp;issue%5Bparent_issue_id%5D=&amp;no_flash=1">Delete link to subtask</a><a title="Actions" class="icon-only icon-actions js-contextmenu" href="#">Actions</a></td></tr><tr class="issue issue-80247 hascontextmenu issue tracker-1 status-2 priority-4 priority-default child"><td class="checkbox"><input type="checkbox" name="ids[]" value="80247" /></td><td class="subject"><a class="issue tracker-1 status-2 priority-4 priority-default child" href="/issues/80247">Task #80247</a>: CourseKey Integration: Requests Based on Queue: Очередь отправки: Добавить фоновый скрипт send-coursekey-requests</td><td class="status">In Progress</td><td class="assigned_to"><a class="user active" href="/users/246">Maksim Fomin</a></td><td class="start_date"></td><td class="due_date"></td><td class="done_ratio"></td><td class="buttons"><a data-confirm="Are you sure?" title="Delete link to subtask" class="icon-only icon-link-break" rel="nofollow" data-method="put" href="/issues/80247?back_url=%2Fissues%2F80238&amp;issue%5Bparent_issue_id%5D=&amp;no_flash=1">Delete link to subtask</a><a title="Actions" class="icon-only icon-actions js-contextmenu" href="#">Actions</a></td></tr><tr class="issue issue-80248 hascontextmenu issue tracker-1 status-10 priority-4 priority-default child assigned-to-me"><td class="checkbox"><input type="checkbox" name="ids[]" value="80248" /></td><td class="subject"><a class="issue tracker-1 status-10 priority-4 priority-default child assigned-to-me" href="/issues/80248">Task #80248</a>: CourseKey Integration: Requests Based on Queue: Очередь отправки: Добавить класс Chain</td><td class="status">Testing</td><td class="assigned_to"><a class="user active" href="/users/109">Mikhail Guschin</a></td><td class="start_date"></td><td class="due_date"></td><td class="done_ratio"></td><td class="buttons"><a data-confirm="Are you sure?" title="Delete link to subtask" class="icon-only icon-link-break" rel="nofollow" data-method="put" href="/issues/80248?back_url=%2Fissues%2F80238&amp;issue%5Bparent_issue_id%5D=&amp;no_flash=1">Delete link to subtask</a><a title="Actions" class="icon-only icon-actions js-contextmenu" href="#">Actions</a></td></tr><tr class="issue issue-80249 hascontextmenu issue tracker-1 status-2 priority-4 priority-default child"><td class="checkbox"><input type="checkbox" name="ids[]" value="80249" /></td><td class="subject"><a class="issue tracker-1 status-2 priority-4 priority-default child" href="/issues/80249">Task #80249</a>: CourseKey Integration: Requests Based on Queue: Очередь отправки: Добавить класс ChainSendPolicy</td><td class="status">In Progress</td><td class="assigned_to"><a class="user active" href="/users/246">Maksim Fomin</a></td><td class="start_date"></td><td class="due_date"></td><td class="done_ratio"></td><td class="buttons"><a data-confirm="Are you sure?" title="Delete link to subtask" class="icon-only icon-link-break" rel="nofollow" data-method="put" href="/issues/80249?back_url=%2Fissues%2F80238&amp;issue%5Bparent_issue_id%5D=&amp;no_flash=1">Delete link to subtask</a><a title="Actions" class="icon-only icon-actions js-contextmenu" href="#">Actions</a></td></tr></table>
</form>
</div>
<hr />
<div id="relations">
<div class="contextual">
<a onclick="$(&#39;#new-relation-form&#39;).toggle(); $(&#39;#relation_issue_to_id:visible&#39;).focus(); return false;" href="#">Add</a>
</div>
<p>
<strong>Related issues</strong>
</p>
<form class="new_relation" id="new-relation-form" style="display: none;" action="/issues/80238/relations" accept-charset="UTF-8" data-remote="true" name="new-relation-form-5031d255" method="post"><input name="utf8" type="hidden" value="&#x2713;" autocomplete="off" />
<p><select onchange="setPredecessorFieldsVisibility();" name="relation[relation_type]" id="relation_relation_type"><option selected="selected" value="relates">Related to</option>
<option value="duplicates">Is duplicate of</option>
<option value="duplicated">Has duplicate</option>
<option value="blocks">Blocks</option>
<option value="blocked">Blocked by</option>
<option value="precedes">Precedes</option>
<option value="follows">Follows</option>
<option value="copied_to">Copied to</option>
<option value="copied_from">Copied from</option></select>
Issue #<input value="" size="10" type="text" name="relation[issue_to_id]" id="relation_issue_to_id" />
<span id="predecessor_fields" style="display:none;">
Delay: <input size="3" type="text" name="relation[delay]" id="relation_delay" /> days
</span>
<input type="submit" name="commit" value="Add" data-disable-with="Add" />
<a href="#" onclick="$(&quot;#new-relation-form&quot;).hide();; return false;">Cancel</a>
</p>
<script>
//<![CDATA[
multipleAutocompleteField('relation_issue_to_id', '/issues/auto_complete?issue_id=80238&project_id=gegi-llc-gegi-tasks&scope=all')
//]]>
</script>
<script>
//<![CDATA[
setPredecessorFieldsVisibility();
//]]>
</script>
</form>
</div>
</div>
<div id="history">
<div class="tabs">
<ul>
<li><a id="tab-history" class="selected" onclick="showIssueHistory(&quot;history&quot;, this.href); return false;" href="/issues/80238?tab=history">History</a></li>
<li><a id="tab-notes" onclick="showIssueHistory(&quot;notes&quot;, this.href); return false;" href="/issues/80238?tab=notes">Notes</a></li>
<li><a id="tab-properties" onclick="showIssueHistory(&quot;properties&quot;, this.href); return false;" href="/issues/80238?tab=properties">Property changes</a></li>
</ul>
<div class="tabs-buttons" style="display:none;">
<button class="tab-left" type="button" onclick="moveTabLeft(this);"></button>
<button class="tab-right" type="button" onclick="moveTabRight(this);"></button>
</div>
</div>
<div id="tab-content-history" class="tab-content">
<div id="change-899970" class="journal has-details">
<div id="note-1" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-1">Copy link</a></div></div></span></span>
<a href="#note-1" class="journal-link">#1</a>
</div>
<h4 class='note-header'>
<img alt="" title="Mikhail Guschin" class="gravatar" srcset="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/109">Mikhail Guschin</a> <a title="02/16/2024 15:43" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-899970-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Assignee</strong> set to <i>Mikhail Guschin</i></li>
</ul>
</div>
</div>
<div id="change-899980" class="journal has-details">
<div id="note-2" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-2">Copy link</a></div></div></span></span>
<a href="#note-2" class="journal-link">#2</a>
</div>
<h4 class='note-header'>
<img alt="" title="Mikhail Guschin" class="gravatar" srcset="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/109">Mikhail Guschin</a> <a title="02/16/2024 15:57" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-899980-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Description</strong> updated (<a title="View differences" href="/journals/899980/diff?detail_id=1198398">diff</a>)</li>
<li><strong>Assignee</strong> deleted (<del><i>Mikhail Guschin</i></del>)</li>
</ul>
</div>
</div>
<div id="change-899981" class="journal has-notes">
<div id="note-3" class="note">
<div class="contextual">
<span class="journal-actions"><a title="Quote" class="icon-only icon-comment" data-remote="true" rel="nofollow" data-method="post" href="/issues/80238/quoted?journal_id=899981&amp;journal_indice=3">Quote</a><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-3">Copy link</a></div></div></span></span>
<a href="#note-3" class="journal-link">#3</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/16/2024 15:58" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-899981-private_notes" class=""></span>
<span title="02/16/2024 15:58 by Maksim Fomin" class="update-info">· Edited</span>
</h4>
<div id="journal-899981-notes" class="wiki"><p>важно выбирать полные цепочки - мы можем использовать метку времени для таких цепочек. Например колонку group: а туда вставлять timestump.</p></div>
</div>
</div>
<div id="change-899992" class="journal has-details">
<div id="note-4" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-4">Copy link</a></div></div></span></span>
<a href="#note-4" class="journal-link">#4</a>
</div>
<h4 class='note-header'>
<img alt="" title="Mikhail Guschin" class="gravatar" srcset="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/109">Mikhail Guschin</a> <a title="02/16/2024 16:28" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-899992-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Subject</strong> changed from <i>CourseKey Integration: Requests Based on Queue: Очередь отправки</i> to <i>[&amp;] CourseKey Integration: Requests Based on Queue: Очередь отправки</i></li>
</ul>
</div>
</div>
<div id="change-900026" class="journal has-notes">
<div id="note-5" class="note">
<div class="contextual">
<span class="journal-actions"><a title="Quote" class="icon-only icon-comment" data-remote="true" rel="nofollow" data-method="post" href="/issues/80238/quoted?journal_id=900026&amp;journal_indice=5">Quote</a><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-5">Copy link</a></div></div></span></span>
<a href="#note-5" class="journal-link">#5</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/16/2024 17:20" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-900026-private_notes" class=""></span>
<span title="02/16/2024 17:20 by Maksim Fomin" class="update-info">· Edited</span>
</h4>
<div id="journal-900026-notes" class="wiki"><p>Maksim Fomin wrote in <a href="#note-3">#note-3</a>:</p>
<blockquote>
<p>важно выбирать полные цепочки - мы можем использовать метку времени для таких цепочек. Например колонку group: а туда вставлять timestump.</p>
</blockquote>
<p>Договорились, что можно использовать Uuid для группировки цепочек. Если его нет в проекте, то подключу библиотеку <a href="https://packagist.org/packages/ramsey/uuid" class="external">uuid</a></p></div>
</div>
</div>
<div id="change-900027" class="journal has-details">
<div id="note-6" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-6">Copy link</a></div></div></span></span>
<a href="#note-6" class="journal-link">#6</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/16/2024 17:22" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-900027-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Subtask</strong> <i>#80245</i> added</li>
</ul>
</div>
</div>
<div id="change-900028" class="journal has-details">
<div id="note-7" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-7">Copy link</a></div></div></span></span>
<a href="#note-7" class="journal-link">#7</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/16/2024 17:23" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-900028-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Subtask</strong> <i>#80246</i> added</li>
</ul>
</div>
</div>
<div id="change-900029" class="journal has-details">
<div id="note-8" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-8">Copy link</a></div></div></span></span>
<a href="#note-8" class="journal-link">#8</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/16/2024 17:24" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-900029-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Subtask</strong> <i>#80247</i> added</li>
</ul>
</div>
</div>
<div id="change-900030" class="journal has-details">
<div id="note-9" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-9">Copy link</a></div></div></span></span>
<a href="#note-9" class="journal-link">#9</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/16/2024 17:25" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-900030-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Subtask</strong> <i>#80248</i> added</li>
</ul>
</div>
</div>
<div id="change-900031" class="journal has-details">
<div id="note-10" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-10">Copy link</a></div></div></span></span>
<a href="#note-10" class="journal-link">#10</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/16/2024 17:25" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-16">11 days</a> ago
<span id="journal-900031-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Subtask</strong> <i>#80249</i> added</li>
</ul>
</div>
</div>
<div id="change-901889" class="journal has-details">
<div id="note-11" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-11">Copy link</a></div></div></span></span>
<a href="#note-11" class="journal-link">#11</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/21/2024 19:15" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-21">6 days</a> ago
<span id="journal-901889-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Description</strong> updated (<a title="View differences" href="/journals/901889/diff?detail_id=1200767">diff</a>)</li>
</ul>
</div>
</div>
<div id="change-902103" class="journal has-details">
<div id="note-12" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-12">Copy link</a></div></div></span></span>
<a href="#note-12" class="journal-link">#12</a>
</div>
<h4 class='note-header'>
<img alt="" title="Mikhail Guschin" class="gravatar" srcset="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/109">Mikhail Guschin</a> <a title="02/22/2024 12:21" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-22">5 days</a> ago
<span id="journal-902103-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Status</strong> changed from <i>New</i> to <i>In Progress</i></li>
<li><strong>Assignee</strong> set to <i>Maksim Fomin</i></li>
<li><strong>Estimated time</strong> set to <i>3.00 h</i></li>
</ul>
</div>
</div>
<div id="change-902104" class="journal has-details">
<div id="note-13" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-13">Copy link</a></div></div></span></span>
<a href="#note-13" class="journal-link">#13</a>
</div>
<h4 class='note-header'>
<img alt="" title="Mikhail Guschin" class="gravatar" srcset="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/109">Mikhail Guschin</a> <a title="02/22/2024 12:22" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-22">5 days</a> ago
<span id="journal-902104-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Assignee</strong> changed from <i>Maksim Fomin</i> to <i>Mikhail Guschin</i></li>
</ul>
</div>
</div>
<div id="change-902143" class="journal has-details">
<div id="note-14" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-14">Copy link</a></div></div></span></span>
<a href="#note-14" class="journal-link">#14</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/22/2024 13:40" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-22">5 days</a> ago
<span id="journal-902143-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Assignee</strong> changed from <i>Mikhail Guschin</i> to <i>Maksim Fomin</i></li>
</ul>
</div>
</div>
<div id="change-902374" class="journal has-details">
<div id="note-15" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-15">Copy link</a></div></div></span></span>
<a href="#note-15" class="journal-link">#15</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/22/2024 21:27" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-22">5 days</a> ago
<span id="journal-902374-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Description</strong> updated (<a title="View differences" href="/journals/902374/diff?detail_id=1201440">diff</a>)</li>
</ul>
</div>
</div>
<div id="change-902681" class="journal has-notes">
<div id="note-16" class="note">
<div class="contextual">
<span class="journal-actions"><a title="Quote" class="icon-only icon-comment" data-remote="true" rel="nofollow" data-method="post" href="/issues/80238/quoted?journal_id=902681&amp;journal_indice=16">Quote</a><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-16">Copy link</a></div></div></span></span>
<a href="#note-16" class="journal-link">#16</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/23/2024 17:42" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-23">4 days</a> ago
<span id="journal-902681-private_notes" class=""></span>
<span title="02/26/2024 15:43 by Maksim Fomin" class="update-info">· Edited</span>
</h4>
<div id="journal-902681-notes" class="wiki">На данный момент принцип работы следующий:
<ol>
<li>В монолите при обновлении сущностей нужно будет вызывать:<br /><pre>
// На данный момент собирается массив цепочки.
$chainJobs = [
new AddCourse('1','1','1','1','1','1'),
new AddUser('1','1','1','1','1','1','1')
];
$chain = new Chain($chainJobs);
$chain-&gt;Dispatch();
$chain-&gt;Dispatch(); // Сохранит цепочку в таблице.
</pre></li>
<li>Фоновый скрипт читает очередь, обходит цепочки и устанавливает статусы:<br /><pre>
$limit = 10;
/** @var SendCourseKeyRequest $command */
$command = SendCourseKeyRequest::Get();
$command-&gt;HandleRequests($limit);
</pre></li>
</ol>
<p>В теории ещё можно проходить в цикле и пытаться прочитать 50 строк беря по 5 полных цепочек, т.к. коллекция очищается.</p></div>
</div>
</div>
<div id="change-902682" class="journal has-details">
<div id="note-17" class="note">
<div class="contextual">
<span class="journal-actions"><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-17">Copy link</a></div></div></span></span>
<a href="#note-17" class="journal-link">#17</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/23/2024 17:44" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-23">4 days</a> ago
<span id="journal-902682-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>Description</strong> updated (<a title="View differences" href="/journals/902682/diff?detail_id=1201834">diff</a>)</li>
</ul>
</div>
</div>
<div id="change-902689" class="journal has-notes has-details">
<div id="note-18" class="note">
<div class="contextual">
<span class="journal-actions"><a title="Quote" class="icon-only icon-comment" data-remote="true" rel="nofollow" data-method="post" href="/issues/80238/quoted?journal_id=902689&amp;journal_indice=18">Quote</a><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-18">Copy link</a></div></div></span></span>
<a href="#note-18" class="journal-link">#18</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/23/2024 17:57" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-23">4 days</a> ago
<span id="journal-902689-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>File</strong> <a href="/attachments/36342">clipboard-202402231857-4s31f.png</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/36342/clipboard-202402231857-4s31f.png">clipboard-202402231857-4s31f.png</a> added</li>
</ul>
<div class="thumbnails">
<div><a title="clipboard-202402231857-4s31f.png" href="/attachments/36342"><img srcset="/attachments/thumbnail/36342/800 2x" style="max-width: 400px; max-height: 400px;" loading="lazy" src="/attachments/thumbnail/36342/800" /></a></div>
</div>
<div id="journal-902689-notes" class="wiki"><p><img src="/attachments/download/36342/clipboard-202402231857-4s31f.png" title="Классы" alt="Классы" loading="lazy" style="width:300px;" alt="" /></p></div>
</div>
</div>
<div id="change-903197" class="journal has-notes">
<div id="note-19" class="note">
<div class="contextual">
<span class="journal-actions"><a title="Quote" class="icon-only icon-comment" data-remote="true" rel="nofollow" data-method="post" href="/issues/80238/quoted?journal_id=903197&amp;journal_indice=19">Quote</a> <a title="Edit" class="icon-only icon-edit" data-remote="true" data-method="get" href="/journals/903197/edit">Edit</a><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-19">Copy link</a> <a data-confirm="Are you sure?" class="icon icon-del" data-remote="true" rel="nofollow" data-method="put" href="/journals/903197?journal%5Bnotes%5D=">Delete</a></div></div></span></span>
<a href="#note-19" class="journal-link">#19</a>
</div>
<h4 class='note-header'>
<img alt="" title="Mikhail Guschin" class="gravatar" srcset="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/3a21676d18a0075f6ff0c4f30e12acaa?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/109">Mikhail Guschin</a> <a title="02/26/2024 13:51" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-26">about 22 hours</a> ago
<span id="journal-903197-private_notes" class=""></span>
</h4>
<div id="journal-903197-notes" class="wiki"><p>Maksim Fomin wrote in <a href="#note-5">#note-5</a>:</p>
<blockquote>
<p>Maksim Fomin wrote in <a href="#note-3">#note-3</a>:</p>
<blockquote>
<p>важно выбирать полные цепочки - мы можем использовать метку времени для таких цепочек. Например колонку group: а туда вставлять timestump.</p>
</blockquote>
<p>Договорились, что можно использовать Uuid для группировки цепочек. Если его нет в проекте, то подключу библиотеку <a href="https://packagist.org/packages/ramsey/uuid" class="external">uuid</a></p>
</blockquote>
<p>Ок. Библиотека выглядит живой (крайний стабильный релиз Ноябрь 2023).</p></div>
</div>
</div>
<div id="change-903303" class="journal has-notes has-details">
<div id="note-20" class="note">
<div class="contextual">
<span class="journal-actions"><a title="Quote" class="icon-only icon-comment" data-remote="true" rel="nofollow" data-method="post" href="/issues/80238/quoted?journal_id=903303&amp;journal_indice=20">Quote</a><span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items"><a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238#note-20">Copy link</a></div></div></span></span>
<a href="#note-20" class="journal-link">#20</a>
</div>
<h4 class='note-header'>
<img alt="" title="Maksim Fomin" class="gravatar" srcset="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=48&amp;default=identicon 2x" src="https://www.gravatar.com/avatar/dfae39cc4ab4115da995d70d6c33d648?rating=PG&amp;size=24&amp;default=identicon" />
Updated by <a class="user active" href="/users/246">Maksim Fomin</a> <a title="02/26/2024 16:37" href="/projects/gegi-llc-gegi-tasks/activity?from=2024-02-26">about 19 hours</a> ago
<span id="journal-903303-private_notes" class=""></span>
</h4>
<ul class="details">
<li><strong>File</strong> <a href="/attachments/36357">clipboard-202402261726-up7rv.png</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/36357/clipboard-202402261726-up7rv.png">clipboard-202402261726-up7rv.png</a> added</li>
</ul>
<div class="thumbnails">
<div><a title="clipboard-202402261726-up7rv.png" href="/attachments/36357"><img srcset="/attachments/thumbnail/36357/800 2x" style="max-width: 400px; max-height: 400px;" loading="lazy" src="/attachments/thumbnail/36357/800" /></a></div>
</div>
<div id="journal-903303-notes" class="wiki">Что реализовано на данный момент:
<ol>
<li>Таблица
<table>
<tr>
<td>IsSent</td>
<td>bool</td>
</tr>
<tr>
<td>SentAt</td>
<td>datetime</td>
</tr>
<tr>
<td>Payload</td>
<td>json</td>
</tr>
</table></li>
</ol>
<ol>
<li>Классы
<ol>
<li>Слева классы dto(Job или Command), они совпадают с действием или маршрутом которое нужно совершить в цепочке. Параметры отличаются для каждого маршрута, поэтому и список свойств я решил разделить на разные dto. Далее будет проще понять, что за операция с данными нужна.</li>
<li>Посредине классы для работы с цепочкой очереди(задачами). Chain - содержит одну Request запись из коллекции с которой производит операции сохранения и обновления статусов. Содержит список массив Jobs, который может передать классу ChainSendPolicy.</li>
<li>Справа классы коллекции для работы с таблицей. Умеют кодировать payload в json и декодировать обратно в полноценные объекты для дальнейшей работы. В коллекции есть методы для получения списка коллекций с лимитом и offset для пагинации.<br /><img src="/attachments/download/36357/clipboard-202402261726-up7rv.png" title="2 версия класов" alt="2 версия класов" loading="lazy" style="width:350px;" alt="" /></li>
</ol></li>
</ol></div>
</div>
</div>
</div>
<script>
//<![CDATA[
showIssueHistory("history", this.href)
//]]>
</script>
</div>
<div style="clear: both;"></div>
<div class="contextual">
<a onclick="showAndScrollTo(&quot;update&quot;, &quot;issue_notes&quot;); return false;" class="icon icon-edit" href="/issues/80238/edit">Edit</a>
<a class="icon icon-time-add" href="/issues/80238/time_entries/new">Log time</a>
<a class="issue-80238-watcher icon icon-fav-off" data-remote="true" rel="nofollow" data-method="post" href="/watchers/watch?object_id=80238&amp;object_type=issue">Watch</a>
<a class="icon icon-copy" href="/projects/gegi-llc-gegi-tasks/issues/80238/copy">Copy</a>
<span class="drdn"><span class="drdn-trigger"><span class="icon-only icon-actions" title="Actions">Actions</span></span><div class="drdn-content"><div class="drdn-items">
<a href="#" onclick="copyTextToClipboard(this);; return false;" class="icon icon-copy-link" data-clipboard-text="https://redmine.gegi.co/issues/80238">Copy link</a>
</div></div></span></div>
<div style="clear: both;"></div>
<div id="update" style="display:none;">
<h3>Edit</h3>
<form class="edit_issue" id="issue-form" enctype="multipart/form-data" action="/issues/80238" accept-charset="UTF-8" name="issue-form-0d55567f" method="post"><input name="utf8" type="hidden" value="&#x2713;" autocomplete="off" /><input type="hidden" name="_method" value="patch" autocomplete="off" /><input type="hidden" name="authenticity_token" value="uz6ezJLA1DH6nCvjfsYEIMIOKxlggQC8CF4j9B9/t9yzFaboUKE+e00rChp+ZQ7pEWR1E026Yd8QRMSzevCKAA==" autocomplete="off" />
<div class="box">
<fieldset class="tabular"><legend>Change properties</legend>
<div id="all_attributes">
<input type="hidden" name="form_update_triggered_by" id="form_update_triggered_by" value="" autocomplete="off" />
<p><label for="issue_project_id">Project<span class="required"> *</span></label><select onchange="updateIssueFrom(&#39;/issues/80238/edit.js&#39;, this)" name="issue[project_id]" id="issue_project_id"><option value="32">GEGI LLC</option><option value="53">&nbsp;&nbsp;&#187; Daily Reports</option><option value="47">&nbsp;&nbsp;&#187; GEGI SIS</option><option value="34" selected="selected">&nbsp;&nbsp;&nbsp;&nbsp;&#187; GEGI Monolith</option><option value="59">&nbsp;&nbsp;&nbsp;&nbsp;&#187; GEGI Services</option><option value="60">&nbsp;&nbsp;&nbsp;&nbsp;&#187; User Docs &amp; Rollout</option><option value="61">&nbsp;&nbsp;&#187; GEGI Website</option><option value="45">&nbsp;&nbsp;&#187; Customer Care Team</option><option value="48">&nbsp;&nbsp;&#187; Data Analysts Team</option><option value="35">&nbsp;&nbsp;&#187; Infrastructure Team</option><option value="33">&nbsp;&nbsp;&#187; User Stories</option></select></p>
<p>
<label for="issue_tracker_id">Tracker<span class="required"> *</span></label><select onchange="updateIssueFrom(&#39;/issues/80238/edit.js&#39;, this)" title="" name="issue[tracker_id]" id="issue_tracker_id"><option selected="selected" value="1">Task</option>
<option value="14">Bug</option></select>
</p>
<script>
//<![CDATA[
function selectTracker(id) {
var target = $('#issue_tracker_id');
target.attr("selected", false);
target.find('option[value="' + id + '"]').prop('selected', true);
target.trigger('change');
hideModal('#trackers_description h3');
}
//]]>
</script>
<p><label for="issue_subject">Subject<span class="required"> *</span></label><input size="80" maxlength="255" type="text" value="[&amp;] CourseKey Integration: Requests Based on Queue: Очередь отправки" name="issue[subject]" id="issue_subject" /></p>
<p>
<label for="issue_description">Description<span class="required"> *</span></label>
<a href="#" onclick="$(this).hide(); $(&quot;#issue_description_and_toolbar&quot;).show(); return false;"><span class="icon icon-edit">Edit</span></a>
<span id="issue_description_and_toolbar" style="display:none">
<textarea cols="60" class="wiki-edit" rows="20" data-auto-complete="true" name="issue[description]" id="issue_description">
Доработать очередь отправки (таблица @coursekey_requests.sql@):
# Добавить поле bool для хранения факта отправки. Добавить Индекс.
# Добавить поле для хранения datetime отправки.
# Добавить поля для поддержки цепочек (chain): номер цепочки, порядковый номер запроса в цепочке.
# Поменять типы json полей на json (например RequestParams).
----
Добавить класс @GEGI\CourseKey\Requests\Request@ для работы с coursekey_requests.sql.
# Наследовать его от CollectionItem, т.к. коллекция нужна будет нам чтобы массово сохранять ответы в БД.
# Свойства из БД.
----
Добавить фоновый скрипт @send-coursekey-requests.php@:
# Запускается раз в N минут по настройке &quot;Period of Synchronization, Minutes&quot;:https://dev.app.gegi.co/admin/school-settings/edit?name=System_CourseKeySyncPeriod.
Работает только если включена &quot;Enable CourseKey Synchronization&quot;:https://dev.app.gegi.co/admin/school-settings/edit?name=System_CourseKeyEnableSync.
# Выбирает все не отправленные записи coursekey_requests.sql в коллекцию:
# сортирует их по номеру цепочки и по порядковому номеру запроса в цепочке.
# ограничивает количество не большими порциями (важно выбирать полные цепочки), т.к. отправка частая.
# Отправляет их один за другим и фиксирует ответы в объектах. Затем массово сохраняет их в БД.
# Если запрос в цепочке выполнился с ошибкой:
## Фиксирует ошибку.
## Решает остановить ли цепочку. Нужен гибкий способ настраивать такие решения (будет отдельный класс @ChainSendPolicy@). Если остановить, то останавливает и переходит к следующей цепочке. Если можно продолжать, то продолжает.
# Для каждого запроса добавляет фоновую задачу (dispatcher task) пост-обработки. Так делаем, потому что бывают &quot;тяжелые&quot; алгоритмы (например пересчет SAP).
## Фиксирует в отдельном поле Id такой задачи и статус. Таск пост-обработчик после выполнения меняет этот статус.
----
Добавить класс @GEGI\CourseKey\Requests\Chain@ для работы с цепочками:
# Содержит массив запросов @GEGI\CourseKey\Requests\Request@ с порядковыми номерами (можно использовать индексы массива пронумерованные от 1).
# Содержит объект @GEGI\CourseKey\Requests\ChainSendPolicy@ которая объясняет сценарий действий если при отправке в цепочке есть ошибка.
----
Добавить класс @GEGI\CourseKey\Requests\ChainSendPolicy@ для описания политик обработки ошибок:
# Содержит имя.
# Содержит метод, который на переданный код ответа ({200, ОК}, {400, User Exists} и др.) возвращает сигнал, что делать: продолжить запросы в цепочке, остановить, повторить, отменить сделанные запросы и др.
h2. Results
Разработка ведётся в ветке: &quot;feature/79114-coursekey-integration-requests-based-on-queue&quot;:https://github.com/gegillc/gegi-monolith/tree/feature/79114-coursekey-integration-requests-based-on-queue.
# Доработал очередь отправки. Добавлены новые колонки.
# Добавил коллекции для работы с таблицей.
# Добавил фоновый скрипт.
# Добавил класс Chain - который работает с цепочкой.
# Добавил прототип класса ChainSendPolicy.</textarea>
</span></p>
<script>
//<![CDATA[
var wikiToolbar = new jsToolBar(document.getElementById('issue_description')); wikiToolbar.setHelpLink('/help/en/wiki_syntax_textile.html'); wikiToolbar.setPreviewUrl('/issues/preview?issue_id=80238&project_id=gegi-llc-gegi-tasks'); wikiToolbar.draw();
//]]>
</script>
<div id="attributes" class="attributes">
<div class="splitcontent">
<div class="splitcontentleft">
<p>
<label for="issue_status_id">Status<span class="required"> *</span></label><select onchange="updateIssueFrom(&#39;/issues/80238/edit.js&#39;, this)" name="issue[status_id]" id="issue_status_id"><option value="1">New</option>
<option selected="selected" value="2">In Progress</option>
<option value="10">Testing</option></select>
<span class="icon-only icon-warning" title="This issue cannot be closed because it has at least one open subtask.">This issue cannot be closed because it has at least one open subtask.</span>
</p>
<script>
//<![CDATA[
function selectIssueStatus(id) {
var target = $('#issue_status_id');
target.attr("selected", false);
target.find('option[value="' + id + '"]').prop('selected', true);
target.trigger('change');
hideModal('#issue_statuses_description h3');
}
//]]>
</script>
<p><label for="issue_priority_id">Priority<span class="required"> *</span></label><select name="issue[priority_id]" id="issue_priority_id"><option value="3">Low</option>
<option selected="selected" value="4">Normal</option>
<option value="5">High</option>
<option value="6">Urgent</option>
<option value="7">Immediate</option></select></p>
<p>
<label for="issue_assigned_to_id">Assignee</label><select name="issue[assigned_to_id]" id="issue_assigned_to_id"><option value="">&nbsp;</option>
<option value="109">&lt;&lt; me &gt;&gt;</option><option value="237">Aleksandr Golubev</option><option value="251">Aleksandr Valenta</option><option value="253">Aleksei Nechaev</option><option value="80">Alexander Lyakh</option><option value="6">Alexander Ogurtsov</option><option value="254">Alexander Starikov</option><option value="210">Alexis Rodiz</option><option value="232">Andrei Ivashkin</option><option value="176">Andrey Golovinov</option><option value="250">Andrey Izmaylov</option><option value="33">Anton Dmitriev</option><option value="189">Anton Pupyshev</option><option value="249">Danil Nemtsev</option><option value="127">Dmitry Ermoshkin</option><option value="172">Dmitry Polikarpov</option><option value="200">Evgeniy Kalabkin</option><option value="206">Georgiy Sosnovskiy</option><option value="145">Ivan Gribko</option><option value="197">Ivan Mihalash</option><option value="218">Kseniya Vidyakina</option><option value="246" selected="selected">Maksim Fomin</option><option value="37">Maksim Medvedev</option><option value="109">Mikhail Guschin</option><option value="227">Mikhail Khlevin</option><option value="79">Mikhail Nikitin</option><option value="243">Sergei Safonov</option><option value="135">Sergey Tsikra</option><option value="166">Tanya Smoliarova</option><option value="128">Valeriya Tkach</option><option value="74">Vika Berestiana</option><option value="188">Violetta Gerasenko</option><option value="179">Vlada Golubova</option><optgroup label="Groups"><option value="150">Compliance: Leads</option><option value="149">Customer Care: Leads</option><option value="85">Customer Care: Specialists</option><option value="87">Development: Dev Leads</option><option value="100">Development: Developers</option><option value="211">Development: Developers (Alexis)</option><option value="143">Development: Project Managers</option><option value="182">Infrastructure: DevOps</option></optgroup></select>
<a class="assign-to-me-link" href="#" data-id="109">Assign to me</a>
</p>
<p><label for="issue_fixed_version_id">Target version<span class="required"> *</span></label><select name="issue[fixed_version_id]" id="issue_fixed_version_id"><option value="">&nbsp;</option>
<option value="997">4.71.0 (02/24)</option>
<option value="1001">4.72.0 (03/24)</option>
<option selected="selected" value="927">4.x.x Dev</option>
<option value="945">4.x.x Trunk</option></select>
</p>
</div>
<div class="splitcontentright">
<p id="parent_issue"><label for="issue_parent_issue_id">Parent task</label><input size="10" onchange="updateIssueFrom(&#39;/issues/80238/edit.js&#39;, this)" type="text" value="79968" name="issue[parent_issue_id]" id="issue_parent_issue_id" /></p>
<script>
//<![CDATA[
observeAutocompleteField('issue_parent_issue_id', '/issues/auto_complete?issue_id=80238&project_id=gegi-llc-gegi-tasks&scope=system&status=o')
//]]>
</script>
<p id="start_date_area">
<label for="issue_start_date">Start date</label><input max="9999-12-31" size="10" type="date" name="issue[start_date]" id="issue_start_date" />
<script>
//<![CDATA[
$(function() { $('#issue_start_date').addClass('date').datepickerFallback(datepickerOptions); });
//]]>
</script>
</p>
<p id="due_date_area">
<label for="issue_due_date">Due date</label><input max="9999-12-31" size="10" type="date" name="issue[due_date]" id="issue_due_date" />
<script>
//<![CDATA[
$(function() { $('#issue_due_date').addClass('date').datepickerFallback(datepickerOptions); });
//]]>
</script>
</p>
<p><label for="issue_estimated_hours">Estimated time</label><input size="3" value="3.00" type="text" name="issue[estimated_hours]" id="issue_estimated_hours" /> Hours</p>
</div>
</div>
<div class="splitcontent">
<div class="splitcontentleft">
<p><label for="issue_custom_field_values_24"><span>Tech Support</span></label><select name="issue[custom_field_values][24]" id="issue_custom_field_values_24" class="list_cf cf_24" placeholder=""><option value="">&nbsp;</option><option selected="selected" value="No">No</option>
<option value="AB (Accounting &amp; Business)">AB (Accounting &amp; Business)</option>
<option value="CK (CourseKey)">CK (CourseKey)</option>
<option value="FA (Financial Aid)">FA (Financial Aid)</option>
<option value="RS (Reporting System)">RS (Reporting System)</option>
<option value="TT (Task Team)">TT (Task Team)</option></select></p>
</div><div class="splitcontentright">
</div>
</div>
</div>
<script>
//<![CDATA[
rm = window.rm || {};rm.AutoComplete = rm.AutoComplete || {};rm.AutoComplete.dataSources = JSON.parse('{"issues":"/issues/auto_complete?project_id=gegi-llc-gegi-tasks\u0026q=","wiki_pages":"/wiki_pages/auto_complete?project_id=gegi-llc-gegi-tasks\u0026q="}');
//]]>
</script>
<script>
//<![CDATA[
$(document).ready(function(){
$("#issue_tracker_id, #issue_status_id").each(function(){
$(this).val($(this).find("option[selected=selected]").val());
});
$(".assign-to-me-link").click(function(event){
event.preventDefault();
var element = $(event.target);
$('#issue_assigned_to_id').val(element.data('id'));
element.hide();
});
$('#issue_assigned_to_id').change(function(event){
var assign_to_me_link = $(".assign-to-me-link");
if (assign_to_me_link.length > 0) {
var user_id = $(event.target).val();
var current_user_id = assign_to_me_link.data('id');
if (user_id == current_user_id) {
assign_to_me_link.hide();
} else {
assign_to_me_link.show();
}
}
});
});
//]]>
</script>
</div>
</fieldset>
<fieldset class="tabular" id="log_time"><legend>Log time</legend>
<div class="splitcontent">
<div class="splitcontentleft">
<p><label for="time_entry_hours">Spent time</label><input size="6" value="" type="text" name="time_entry[hours]" id="time_entry_hours" /> Hours</p>
</div>
<div class="splitcontentright">
<p><label for="time_entry_activity_id">Activity</label><select name="time_entry[activity_id]" id="time_entry_activity_id"><option selected="selected" value="">--- Please select ---</option>
<option value="25">Story: Planning</option>
<option value="19">Task: Working</option>
<option value="11">Task: Programming</option>
<option value="14">Task: Testing</option>
<option value="21">Docs: External (for customers)</option>
<option value="17">Docs: Internal (for us)</option>
<option value="20">Support: Customer Care</option>
<option value="29">Support: Compliance</option>
<option value="27">Support: Learning</option>
<option value="26">Support: Waiting</option>
<option value="12">Other</option></select></p>
</div>
</div>
<p><label for="time_entry_comments">Comment</label><input size="60" type="text" name="time_entry[comments]" id="time_entry_comments" /></p>
</fieldset>
<fieldset id="add_notes"><legend>Notes</legend>
<textarea cols="60" rows="10" class="wiki-edit" data-auto-complete="true" name="issue[notes]" id="issue_notes">
</textarea>
<script>
//<![CDATA[
var wikiToolbar = new jsToolBar(document.getElementById('issue_notes')); wikiToolbar.setHelpLink('/help/en/wiki_syntax_textile.html'); wikiToolbar.setPreviewUrl('/issues/preview?issue_id=80238&project_id=gegi-llc-gegi-tasks'); wikiToolbar.draw();
//]]>
</script>
</fieldset>
<fieldset id="add_attachments"><legend>Files</legend>
<div class="contextual"><a onclick="$(&#39;#existing-attachments&#39;).toggle(); return false;" href="#">Edit attached files</a></div>
<div id="existing-attachments" style="display:none;">
<span class="existing-attachment">
<input type="text" name="" id="" value="clipboard-202402231857-4s31f.png" class="icon icon-attachment filename" disabled="disabled" />
<label>
<input type="checkbox" name="issue[deleted_attachment_ids][]" value="36342" class="deleted_attachment" /> Delete
</label>
</span>
<span class="existing-attachment">
<input type="text" name="" id="" value="clipboard-202402261726-up7rv.png" class="icon icon-attachment filename" disabled="disabled" />
<label>
<input type="checkbox" name="issue[deleted_attachment_ids][]" value="36357" class="deleted_attachment" /> Delete
</label>
</span>
<hr />
</div>
<div id="new-attachments" style="display:inline-block;">
<span class="attachments_form">
<span class="attachments_fields">
</span>
<span class="add_attachment" style="">
<input type="file" name="attachments[dummy][file]" class="file_selector filedrop" multiple="multiple" onchange="addInputFiles(this);" data-max-number-of-files-message="This file cannot be uploaded because it exceeds the maximum number of files that can be attached simultaneously (10)" data-max-file-size="25845760" data-max-file-size-message="This file cannot be uploaded because it exceeds the maximum allowed file size (24.6 MB)" data-max-concurrent-uploads="2" data-upload-path="/uploads.js" data-param="attachments" data-description="true" data-description-placeholder="Optional description" />
(Maximum size: 24.6 MB)
</span>
</span>
</div>
</fieldset>
</div>
<input autocomplete="off" type="hidden" value="20" name="issue[lock_version]" id="issue_lock_version" />
<input type="hidden" name="last_journal_id" id="last_journal_id" value="903303" autocomplete="off" />
<input type="submit" name="commit" value="Submit" data-disable-with="Submit" />
<a onclick="$(&#39;#update&#39;).hide(); return false;" href="/issues/80238">Cancel</a>
</form>
</div>
<p class="other-formats">Also available in: <span><a class="atom" rel="nofollow" href="/issues/80238.atom?key=9a0e762bc0de6fd11e6a128b812884226e58f668">Atom</a></span>
<span><a class="pdf" rel="nofollow" href="/issues/80238.pdf">PDF</a></span>
</p>
<div style="clear:both;"></div>
</div>
</div>
<div id="footer">
Powered by <a target="_blank" rel="noopener" href="https://www.redmine.org/">Redmine</a> &copy; 2006-2023 Jean-Philippe Lang
</div>
<div id="ajax-indicator" style="display:none;"><span>Loading...</span></div>
<div id="ajax-modal" style="display:none;"></div>
</div>
</body>
</html>