У нашому програмному забезпеченні ми широко використовуємо MDC для відстеження таких речей, як ідентифікатори сесії та імена користувачів для веб-запитів. Це добре працює під час запуску в оригінальній нитці. Однак є багато речей, які потрібно обробити у фоновому режимі. Для цього ми використовуємо класи java.concurrent.ThreadPoolExecutorта java.util.Timerкласи разом із деякими службами виконання асинхронізації. Усі ці служби управляють власним пулом потоків.
Ось що говорить посібник Logback щодо використання MDC в таких умовах:
Копія відображеного діагностичного контексту не завжди може бути успадкована робочими потоками від ініціюючої нитки. Це той випадок, коли java.util.concurrent.Execitors використовується для управління потоками. Наприклад, метод newCchedThreadPool створює ThreadPoolExecutor і, як і інший код об'єднання ниток, має складну логіку створення ниток.
У таких випадках рекомендується MDC.getCopyOfContextMap () викликати в оригінальній (головній) темі перед тим, як подати завдання виконавцю. Коли завдання виконується, як його перша дія, воно повинно викликати MDC.setContextMapValues (), щоб пов’язати збережену копію оригінальних значень MDC з новим керованим потоком виконавця.
Це було б добре, але забути додавання цих дзвінків дуже просто, і не існує простого способу розпізнати проблему, поки не пізно. Єдиний знак з Log4j полягає в тому, що ви отримуєте відсутність інформації про MDC в журналах, а при Logback ви отримуєте застарілу інформацію про MDC (оскільки нитка в пулі протектора успадковує його MDC від першого завдання, яке було виконано на ньому). Обидва є серйозними проблемами у виробничій системі.
Я не бачу в нашій ситуації особливої особливості, але я не зміг знайти багато про цю проблему в Інтернеті. Мабуть, це не те, проти чого багато людей наштовхуються, тому повинен бути спосіб уникнути цього. Що ми робимо тут неправильно?