Блог ·
Пауза, що тримала замовлення відкритим
Очікування всередині потоку тримало запит замовлення відкритим усю свою тривалість. Виправленням став поріг, а не прапорець, і те число виміряли.
Автор: Provibr
Потік може містити очікування. Ви розгортаєте машину, даєте агентові мить, тоді надсилаєте наступний наказ. До цього тижня тим очікуванням був сон усередині запиту, що розпочав потік, а це означало, що клієнт, який робить замовлення, сидів і дивився на кружальце всю тривалість паузи.
Стара верхня межа становила пʼять хвилин. Тому хтось міг збудувати потік, що виглядає цілком розважливо, а наслідком його була пʼятихвилинна форма замовлення.
Тепер, коли виконання може спинитися і бути продовженим робітником, паузі більше не треба відбуватися всередині запиту. Верхня межа зсунулася до тридцяти днів. Проте цікавим питанням є не стеля. Ним є те, де пролягає межа між паузою, яку запит може поглинути, і паузою, що має призупинити виконання.
Поріг виміряли, а не обрали
Тридцять секунд.
Питанням, яке ми поставили, було не «якою довгою може бути пауза», на яке відповіді немає, а «скільки паузи вже терпить запит, у якому виконується цей потік», на яке відповідь є. Тим запитом є замовлення.
Виміряно проти того, що в ньому вже відбувається: вузол дії усталено чекає на наказ шістдесят секунд і його можна налаштувати до трьохсот, а сповіщення з електронною поштою коштує близько половини секунди на одержувача. Пауза, що додає до цього ще півхвилини, є обґрунтованою. Пауза, що додає цілу хвилину, ні.
Тут є пастка, в яку ми навмисно ступили, замість обійти її. Зручним вибором було б поставити поріг на старій верхній межі у триста секунд, бо тоді кожен наявний граф поводиться точно так, як і раніше, і ніхто не дивується. Це також є хибним: воно зберігає цілий клас проблеми, що спонукала до зміни. Графи з паузою між тридцятьма однією і трьомастами секундами тепер таки поводяться інакше. Їхнє замовлення завершується раніше, а решта потоку йде згодом. Це і є поліпшенням, а не його ціною.
Стеля в тридцять днів є продуктовим правилом, а не технічною межею. Механізм очікування залюбки тримав би виконання рік. Року не витримає організація, в якій ніхто не памʼятає, чому виконання відкрите.
Чому це є порогом, а не прапорцем
Очевидною альтернативою є перемикач «чекати тривко» на вузлі. Ми його не збудували, а причиною є питання, на яке ви не можете відповісти.
Якби прапорець був, коли б ви хотіли вимкнути його? Чесною відповіддю є ніколи. Тривке очікування є подробицею втілення: автор потоку висловлює «спинися тут ось на стільки» і не має думки про те, чи коштує це рядка в базі даних. Налаштування, чиє правильне значення завжди є тим самим, не є налаштуванням, воно є тим, що ви забули вирішити.
Тож автор набирає кількість секунд, а поріг вирішує. Нижче межі обхід просто спить, усередині запиту, не коштуючи нічого. Вище неї виконання записує своє продовження до черги з часом пробудження, а той, хто викликав, повертається негайно.
Крок, що зрештою зʼявляється в журналі виконання, несе прапорець тривкості та справді виміряний час, що минув, а не запитаний, бо це не те саме число, і різниця є єдиним способом побачити, що черга запізнюється.
Потоки, що викликають потоки, і дві межі, кожну з яких перевіряють двічі
Другою половиною цієї роботи є вузол підпотоку: потік, який виконує інший потік і чекає на нього.
Це створює два способи збудувати щось, що ніколи не завершується, і вони виглядають достатньо схоже, щоб виникла спокуса перевіряти їх разом. Це не одне й те саме. Цикл є нескінченним. Надто глибокий ланцюг є скінченним, але задовгим. Якщо ви відповідаєте на обидва однією функцією, про цикл звітують як про «надто глибокий», і автор іде шукати довгий ланцюг, коли його ланцюг завдовжки у два потоки.
Тож питань два, і кожне ставлять двічі.
Уперше їх ставлять, коли потік зберігають, статично, проти інших потоків в організації. Ця перевірка мусить бути там, бо це є єдиним місцем, де можливе добре повідомлення про помилку: воно може назвати потік, що замикає коло.
Вдруге їх ставлять під час виконання. Ця перевірка мусить бути там, бо потоки редагують незалежно. Потік A збережено, і з ним усе гаразд. Тоді хтось редагує потік C, який тепер вказує назад на A. Ніщо не перевірило A наново. Статична перевірка є любʼязністю до автора; динамічна є справжньою гарантією.
Дві подробиці втілення варто назвати. Питання «чи може цей потік досягти самого себе щонайменше за один крок» відповідає і на прямий випадок, і на непрямий одним запитом, а «щонайменше за один» і є цілим означенням: шлях із нуля кроків зробив би так, що кожен потік досягає самого себе. А обхід глибини тримає власний шлях і повертає нескінченність, коли зустрічає потік, що вже на ньому, тож він не зависає рівно на тих вхідних даних, задля яких перевірка циклів існує. Це важить, бо означає, що ці дві перевірки можна запускати в будь-якому порядку, а це означає, що нікому не треба памʼятати правило впорядкування.
Глибину зберігають як стовпець на дочірньому виконанні, а це суперечить нашій звичній лінії, що похідне значення не є стовпцем. Зовнішній ключ до батька стає порожнім, коли батька вилучають, тож після вилучення ланцюгом не можна пройти назад, щоб її перерахувати. Похідне значення, чиє джерело може зникнути, не є похідним.
Запасний годинник є добою, а не пʼятьма хвилинами
Коли дочірнє виконання завершується, воно ставить час пробудження в рядку очікування батька на зараз, і батька підхоплюють протягом десяти секунд. Таким є механізм.
Є також запасний годинник, на випадок, коли цього не стається: контейнер, що впав посеред завершення нащадка, рядок, якого торкнулися рукою. Він становить двадцять чотири години.
Пʼять хвилин були б інстинктивним вибором, і він є хибним. Нащадок, що сидить на погодженні, законно може чекати тридцять днів. Із коротким годинником батько прокидався б тисячі разів за той період, щоб спостерегти, що нічого не змінилося, і кожне з тих пробуджень є запитом HTTP від шлюзу до контейнера вебу. Доба обмежує шкоду від пропущеного сигналу добою і коштує щонайбільше тридцять марних пробуджень за найдовше очікування, яке система дозволяє.
Погодження, про яке нікому не сказали, є застряглим виконанням
Запит на погодження тепер може надіслати листа, і категорія, під якою його надсилають, є власною, а не загальною категорією потоків. Це було навмисним відхиленням від плану.
Загальна категорія потоків іде до всіх, хто має модуль автоматизації. Запит на погодження має йти до людей, які справді можуть його вирішити, а це є іншою і меншою множиною. Тож на категорії є друге сито: сповіщення доправляють лише учасникам, які мають право вирішувати.
Виміряно на нашій тестовій організації: загальна категорія потоків розвʼязалася в трьох одержувачів, а категорія погоджень у двох. Два числа, що різняться, і є цілим доказом того, що сито щось робить.
Клік, що не обрав нічого
Урок вимірювання з цього раунду стосується браузерного тесту, а не продукту.
Наш браузерний помічник має метод кліку, що надсилає натиск і відпускання кнопки миші. На звичайній кнопці це працює. На вузлі в полотні потоку це не робить нічогісінько: панель властивостей лишилася на вузлі тригера, а спадного списку, який ми хотіли змінити, не існувало, і це читається точно як відсутня можливість.
Полотно починає тягнення на опусканні вказівника й викликає setPointerCapture на вузлі. Без попередньої події руху миші й без поля buttons, виставленого на натиску, браузер не дає кліку, який шлях захоплення розпізнає. Додавання цих двох робить вибір негайним.
У тому самому помічнику є друга подробиця. Не клікайте на середині вузла. Середина вузла з портами сидить між точками портів, а ті мають власний обробник вказівника для витягування дроту. Клікайте натомість у лівому верхньому куті заголовка.
Обидві виглядають як вади продукту, коли ви на них натрапляєте, і жодна з них нею не є. Такою є загальна форма проблеми: імітація введення, яка є майже правильною, зазнає невдачі в спосіб, який годі відрізнити від того, що річ, яку ви намагалися випробувати, зламана.
Що ми б записали
- Поріг перемагає прапорець, коли правильне значення прапорця завжди є тим самим. Спитайте, коли б хтось його вимкнув; якщо відповіді немає, не будуйте перемикача.
- Міряйте поріг проти бюджету, в який він має вміститися, а не проти можливості, яку ви обмежуєте.
- Не ставте новий поріг на старій межі лише тому, що тоді нічого не змінюється. Те, що нічого не змінюється, і є проблемою, яку ви розвʼязували.
- Цикл і задовгий ланцюг є різними помилками. Одне повідомлення на обидва відсилає людей не туди.
- Перевіряйте при збереженні заради повідомлення і під час виконання заради гарантії. Сусідні записи змінюються, не перевіряючи наново ваш.
- Пошук, що завершується на власному шляху, можна запускати в будь-якому порядку щодо перевірки, яку він підтримує, а це усуває правило впорядкування, якого ніхто б не памʼятав.
- Похідне значення, чиє джерело можна вилучити, не є похідним. Зберігайте його.
- Розмірюйте запасний годинник проти найдовшого законного очікування, а не проти того, як швидко ви хотіли б помітити.
- Спрямовуйте сповіщення за тим, хто може за ним діяти, а не за тим, до якого модуля воно належить.
- Імітоване введення, яке є майже правильним, зазнає невдачі як зламана можливість. Перевірте, як складова насправді отримує події, перш ніж вірити результатові.
Для ясності про те, чим це є: перевірка злиття пройшла 16 із 16 кроків без жодного рядка невдачі, набір вебу був зеленим на 4583, набори пакунків, шлюзу та інструментів на 7286, тести обходу на 75, перевірки підпотоків на 13, наскрізний запуск проти бази даних розробки на 58, вимірювання одержувачів на 4, а браузерний тест на 31 зі справжнім робітником шлюзу, в якому пауза на девʼяносто секунд поновилася через девʼяносто пʼять секунд, батьківське й дочірнє виконання були повʼязані, надіслали рівно одного листа погодження, а ланцюг із чотирьох і рекурсивне посилання обидва відхилили, назвавши в повідомленні винний ланцюг. Тест редактора був зеленим на 9, а сканування доступності не знайшло нічого на шести сторінках. Не доведено: гілки вичерпання спроб і застарілої заявки, запасний годинник на двадцять чотири години, підпотік усередині циклу, зникле дочірнє виконання, лист до невласника через справжнє надсилання і взагалі нічого проти справжнього гіпервізора.
Із платформної роботи над Provibr. Як обхід узагалі навчився спинятися, описано в Кожен виклик самого себе стояв у хвостовій позиції, а форму самого графа описано в Потік є графом, і граф має бути скінченним.