Инструкция по интеграции утилит контроля качества
Софт А и Софт Б — разные системы → используйте Message Queue
Софт А и Софт Б — одна система → синхронная обработка (без очереди)
Чтобы избежать конфликтов при обработке одной партии несколькими утилитами, используйте формат:
input-{имяУтилиты}-{идентификаторПартии}.csvoutput-{имяУтилиты}-{идентификаторПартии}.jsonПример:
input-Fluorine18FDGQualityChecker-F18-FDG-2026-03-18-A.csvoutput-Fluorine18FDGQualityChecker-F18-FDG-2026-03-18-A.jsonЭто гарантирует, что файлы от разных утилит не перезапишут друг друга, даже если все файлы хранятся в одной папке.
Пошаговая инструкция
1 Экспорт данных в CSV
Что делает Софт А: Экспортирует данные партии в CSV-файл в формате, соответствующем выбранной утилите.
Формат файла: input-{имяУтилиты}-{идентификаторПартии}.csv
Пример: input-DecayCorrector-BATCH-001.csv
Требования:
- Первая строка — заголовки столбцов (точно как в описании утилиты)
- Кодировка файла: UTF-8
- Разделитель: запятая (,)
- Десятичный разделитель: точка (.)
2 Запуск утилиты
Команда:
{имяУтилиты}.exe input-{имяУтилиты}-{идентификаторПартии}.csv output-{имяУтилиты}-{идентификаторПартии}.json
Пример:
Fluorine18FDGQualityChecker.exe input-Fluorine18FDGQualityChecker-F18-FDG-2026-03-18-A.csv output-Fluorine18FDGQualityChecker-F18-FDG-2026-03-18-A.json
Возвращаемое значение:
Exit Code = 0— утилита завершилась успешноExit Code ≠ 0— произошла ошибка (проверьте логи утилиты)
Обработка ошибок: Утилита сама обрабатывает ошибки валидации данных. Если данные некорректны, в output.json будет поле ErrorMessage с описанием ошибки. Если ошибок нет, ErrorMessage = "".
3 Обработка результата
Что делает Софт Б: Читает JSON-файл с результатами и интегрирует их в рабочий процесс.
Файл результата: output-{имяУтилиты}-{идентификаторПартии}.json
Ключевые поля в результате:
| Поле | Тип | Описание |
|---|---|---|
ErrorMessage |
string | Пустая строка = успех, иначе описание ошибки |
Result.AllWithinLimits |
boolean | true = все параметры в пределах нормы, false = есть отклонения |
Result.Recommendation |
string | Текстовая рекомендация («Партия годна», «Требуется повторный анализ» и т.д.) |
Result.Parameters |
object | Детальные результаты по каждому параметру контроля качества |
Действия после обработки:
- Сохранить результаты в базу данных
- Сгенерировать отчёт для оператора
- Обновить статус партии в системе («Прошла КК», «Не прошла КК»)
- Отправить уведомление ответственному лицу при отклонениях
4 Опционально: Асинхронная обработка через Message Queue
Когда использовать: Только если Софт А и Софт Б — это разные системы, работающие на разных серверах.
Сценарий:
- Софт А создаёт файл
input-*.csv - Софт А формирует сообщение для очереди:
UtilityName— имя утилитыInputFile— путь к input-файлуOutputFile— путь к output-файлуBatchId— идентификатор партии
- Софт А отправляет сообщение в очередь и продолжает работу
- Отдельный процесс (потребитель) читает сообщение из очереди
- Потребитель запускает утилиту и дожидается завершения
- Потребитель читает
output-*.jsonи отправляет результат обратно в Софт Б через очередь или напрямую
Рекомендации:
- Используйте надёжные очереди: RabbitMQ, Azure Service Bus, AWS SQS
- Реализуйте механизм повторных попыток при сбоях
- Добавьте таймауты для предотвращения «зависания» задач
- Логируйте все операции для аудита
Сценарий: Разные серверы (Софт А ≠ Софт Б)
Если возможно, подключите папку с файлами как сетевой диск между серверами. Это устраняет необходимость в очереди сообщений и значительно упрощает архитектуру.
1 Общая структура сообщения для очереди
Формат сообщения:
| Поле | Тип | Описание | Обязательное |
|---|---|---|---|
Sender |
string | Имя сервера, отправившего сообщение | Да |
Receiver |
string | Имя сервера-получателя (куда отправить результат) | Да |
UtilityName |
string | Имя утилиты контроля качества | Да |
BatchId |
string | Уникальный идентификатор партии | Да |
InputFileAsBytes |
byte[] | Содержимое input-файла в байтах | Да |
OutputFileAsBytes |
byte[] | Содержимое output-файла в байтах (может быть null) | Нет |
Важно: Пути к файлам (InputFile, OutputFile) не передаются — только содержимое файлов в виде байтов. Это обеспечивает независимость от файловой системы каждого сервера.
Сценарий 1: Утилиты на сервере Софт А
┌─────────────────────────────────────────────────────────────┐
│ Сервер А (Софт А + Утилиты): │
│ 1. Создать input-{util}-{batch}.csv │
│ 2. Выполнить утилиту → output-{util}-{batch}.json │
│ 3. Прочитать оба файла в байты │
│ 4. Сформировать сообщение: │
│ • Sender = "ServerA" │
│ • Receiver = "ServerB" │
│ • InputFileAsBytes = [байты input файла] │
│ • OutputFileAsBytes = [байты output файла] │
│ 5. Отправить сообщение в очередь │
│ 6. Продолжить работу (не ждать ответа) │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Сервер Б (Софт Б): │
│ 7. Прочитать сообщение из очереди │
│ 8. Сохранить InputFileAsBytes → input-{util}-{batch}.csv │
│ 9. Сохранить OutputFileAsBytes → output-{util}-{batch}.json│
│ 10. Обработать результат (обновить статус партии и т.д.) │
└─────────────────────────────────────────────────────────────┘
Сценарий 2: Утилиты на сервере Софт Б
┌─────────────────────────────────────────────────────────────┐
│ Сервер А (Софт А): │
│ 1. Создать input-{util}-{batch}.csv │
│ 2. Прочитать файл в байты │
│ 3. Сформировать сообщение: │
│ • Sender = "ServerA" │
│ • Receiver = "ServerB" │
│ • InputFileAsBytes = [байты input файла] │
│ • OutputFileAsBytes = null │
│ 4. Отправить сообщение в очередь │
│ 5. Продолжить работу │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Сервер Б (Софт Б + Утилиты): │
│ 6. Прочитать сообщение из очереди │
│ 7. Сохранить InputFileAsBytes → input-{util}-{batch}.csv │
│ 8. Выполнить утилиту → output-{util}-{batch}.json │
│ 9. Прочитать результат и обработать │
└─────────────────────────────────────────────────────────────┘
Сценарий 3: Утилиты на отдельном сервере (Сервер В)
┌─────────────────────────────────────────────────────────────┐
│ Сервер А (Софт А): │
│ 1. Создать input-{util}-{batch}.csv │
│ 2. Прочитать файл в байты │
│ 3. Сформировать сообщение: │
│ • Sender = "ServerA" │
│ • Receiver = "ServerV" │
│ • InputFileAsBytes = [байты input файла] │
│ • OutputFileAsBytes = null │
│ 4. Отправить сообщение в очередь │
│ 5. Продолжить работу │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Сервер В (Софт В + Утилиты): │
│ 6. Прочитать сообщение из очереди │
│ 7. Сохранить InputFileAsBytes → input-{util}-{batch}.csv │
│ 8. Выполнить утилиту → output-{util}-{batch}.json │
│ 9. Прочитать результат в байты │
│ 10. Сформировать новое сообщение: │
│ • Sender = "ServerV" │
│ • Receiver = "ServerB" │
│ • InputFileAsBytes = [байты input файла] │
│ • OutputFileAsBytes = [байты output файла] │
│ 11. Отправить сообщение в очередь │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Сервер Б (Софт Б): │
│ 12. Прочитать сообщение из очереди │
│ 13. Сохранить файлы и обработать результат │
└─────────────────────────────────────────────────────────────┘
На сервере с утилитами должно быть запущено приложение (Софт В), которое:
- Читает сообщения из очереди
- Выполняет утилиты контроля качества
- Формирует и отправляет результаты обратно в очередь
- Логирует все операции для аудита
Примечание: Приложение Софт В может быть разработано вами, нами или другим подрядчиком. Мы можем предоставить пример реализации на C# или Python.
Сравнение сценариев
| Сценарий | Преимущества | Недостатки | Когда использовать |
|---|---|---|---|
| Сетевой диск | • Простота реализации • Не нужна очередь сообщений |
• Зависимость от сетевой файловой системы | Когда серверы в одной сети и можно настроить общий доступ к файлам |
| Утилиты на сервере А | • Софт А управляет всем процессом • Софт Б только получает результат |
• Нагрузка на сервер А | Когда сервер А мощный, а сервер Б только для отображения результатов |
| Утилиты на сервере Б | • Разгрузка сервера А | • Софт Б должен уметь запускать утилиты | Когда сервер Б ближе к лаборатории (где генерируются данные) |
| Отдельный сервер В | • Максимальная гибкость и масштабируемость | • Требуется дополнительное приложение Софт В | Когда утилиты должны быть изолированы или когда много серверов А/Б |
Начните с простого сценария (сетевой диск или утилиты на одном из существующих серверов).
Переходите к отдельному серверу В только при необходимости масштабирования или изоляции.
Критические требования
Всегда используйте формат
input-{имяУтилиты}-{идентификаторПартии}.csv и output-{имяУтилиты}-{идентификаторПартии}.json.Это предотвращает конфликты при обработке одной партии несколькими утилитами одновременно.
Утилита всегда возвращает
Exit Code = 0 при успешном запуске (даже если данные не прошли валидацию).Проверяйте поле
ErrorMessage в output.json для определения ошибок валидации данных.
Утилиты работают быстро (обычно < 1 секунды), но для надёжности установите таймаут 30-60 секунд на выполнение.
Утилиты не требуют прав администратора и работают локально. Никакие данные не передаются в интернет.
Integration Guide for QC Utilities
Software A and Software B are different systems → use Message Queue
Software A and Software B are the same system → synchronous processing (no queue needed)
To avoid conflicts when processing a single batch with multiple utilities, use the format:
input-{utilityName}-{batchId}.csvoutput-{utilityName}-{batchId}.jsonExample:
input-Fluorine18FDGQualityChecker-F18-FDG-2026-03-18-A.csvoutput-Fluorine18FDGQualityChecker-F18-FDG-2026-03-18-A.jsonThis ensures files from different utilities won't overwrite each other, even if all files are stored in the same folder.
Step-by-Step Integration Guide
1 Export Data to CSV
What Software A does: Exports batch data to a CSV file in the format required by the selected utility.
File format: input-{utilityName}-{batchId}.csv
Example: input-DecayCorrector-BATCH-001.csv
Requirements:
- First line — column headers (exactly as specified in utility documentation)
- File encoding: UTF-8
- Delimiter: comma (,)
- Decimal separator: period (.)
2 Run the Utility
Command:
{utilityName}.exe input-{utilityName}-{batchId}.csv output-{utilityName}-{batchId}.json
Example:
Fluorine18FDGQualityChecker.exe input-Fluorine18FDGQualityChecker-F18-FDG-2026-03-18-A.csv output-Fluorine18FDGQualityChecker-F18-FDG-2026-03-18-A.json
Return value:
Exit Code = 0— utility completed successfullyExit Code ≠ 0— error occurred (check utility logs)
Error handling: The utility handles data validation errors internally. If data is invalid, the output.json will contain an ErrorMessage field with error description. If no errors, ErrorMessage = "".
3 Process the Result
What Software B does: Reads the JSON result file and integrates it into the workflow.
Result file: output-{utilityName}-{batchId}.json
Key fields in result:
| Field | Type | Description |
|---|---|---|
ErrorMessage |
string | Empty string = success, otherwise error description |
Result.AllWithinLimits |
boolean | true = all parameters within limits, false = deviations found |
Result.Recommendation |
string | Text recommendation ("Batch approved", "Repeat analysis required", etc.) |
Result.Parameters |
object | Detailed results for each QC parameter |
Actions after processing:
- Save results to database
- Generate report for operator
- Update batch status in system ("QC Passed", "QC Failed")
- Send notification to responsible person for deviations
4 Optional: Asynchronous Processing via Message Queue
When to use: Only if Software A and Software B are different systems running on different servers.
Scenario:
- Software A creates
input-*.csvfile - Software A forms queue message:
UtilityName— utility nameInputFile— path to input fileOutputFile— path to output fileBatchId— batch identifier
- Software A sends message to queue and continues working
- Separate process (consumer) reads message from queue
- Consumer runs utility and waits for completion
- Consumer reads
output-*.jsonand sends result back to Software B via queue or directly
Recommendations:
- Use reliable queues: RabbitMQ, Azure Service Bus, AWS SQS
- Implement retry mechanism for failures
- Add timeouts to prevent task "hanging"
- Log all operations for audit purposes
Scenario: Different Servers (Software A ≠ Software B)
If possible, mount the file folder as a network drive between servers. This eliminates the need for a message queue and significantly simplifies the architecture.
1 General Message Structure for Queue
Message format:
| Field | Type | Description | Required |
|---|---|---|---|
Sender |
string | Name of server sending the message | Yes |
Receiver |
string | Name of recipient server (where to send result) | Yes |
UtilityName |
string | Name of QC utility | Yes |
BatchId |
string | Unique batch identifier | Yes |
InputFileAsBytes |
byte[] | Content of input file as bytes | Yes |
OutputFileAsBytes |
byte[] | Content of output file as bytes (may be null) | No |
Important: File paths (InputFile, OutputFile) are NOT transmitted — only file content as bytes. This ensures independence from each server's file system.
Scenario 1: Utilities on Software A Server
┌─────────────────────────────────────────────────────────────┐
│ Server A (Software A + Utilities): │
│ 1. Create input-{util}-{batch}.csv │
│ 2. Run utility → output-{util}-{batch}.json │
│ 3. Read both files into bytes │
│ 4. Form message: │
│ • Sender = "ServerA" │
│ • Receiver = "ServerB" │
│ • InputFileAsBytes = [bytes of input file] │
│ • OutputFileAsBytes = [bytes of output file] │
│ 5. Send message to queue │
│ 6. Continue working (don't wait for response) │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Server B (Software B): │
│ 7. Read message from queue │
│ 8. Save InputFileAsBytes → input-{util}-{batch}.csv │
│ 9. Save OutputFileAsBytes → output-{util}-{batch}.json │
│ 10. Process result (update batch status, etc.) │
└─────────────────────────────────────────────────────────────┘
Scenario 2: Utilities on Software B Server
┌─────────────────────────────────────────────────────────────┐
│ Server A (Software A): │
│ 1. Create input-{util}-{batch}.csv │
│ 2. Read file into bytes │
│ 3. Form message: │
│ • Sender = "ServerA" │
│ • Receiver = "ServerB" │
│ • InputFileAsBytes = [bytes of input file] │
│ • OutputFileAsBytes = null │
│ 4. Send message to queue │
│ 5. Continue working │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Server B (Software B + Utilities): │
│ 6. Read message from queue │
│ 7. Save InputFileAsBytes → input-{util}-{batch}.csv │
│ 8. Run utility → output-{util}-{batch}.json │
│ 9. Read result and process │
└─────────────────────────────────────────────────────────────┘
Scenario 3: Utilities on Separate Server (Server V)
┌─────────────────────────────────────────────────────────────┐
│ Server A (Software A): │
│ 1. Create input-{util}-{batch}.csv │
│ 2. Read file into bytes │
│ 3. Form message: │
│ • Sender = "ServerA" │
│ • Receiver = "ServerV" │
│ • InputFileAsBytes = [bytes of input file] │
│ • OutputFileAsBytes = null │
│ 4. Send message to queue │
│ 5. Continue working │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Server V (Software V + Utilities): │
│ 6. Read message from queue │
│ 7. Save InputFileAsBytes → input-{util}-{batch}.csv │
│ 8. Run utility → output-{util}-{batch}.json │
│ 9. Read result into bytes │
│ 10. Form new message: │
│ • Sender = "ServerV" │
│ • Receiver = "ServerB" │
│ • InputFileAsBytes = [bytes of input file] │
│ • OutputFileAsBytes = [bytes of output file] │
│ 11. Send message to queue │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Server B (Software B): │
│ 12. Read message from queue │
│ 13. Save files and process result │
└─────────────────────────────────────────────────────────────┘
A dedicated application (Software V) must be running on the utility server that:
- Reads messages from the queue
- Executes QC utilities
- Forms and sends results back to the queue
- Logs all operations for audit purposes
Note: Software V application can be developed by you, us, or another contractor. We can provide implementation examples in C# or Python.
Scenario Comparison
| Scenario | Advantages | Disadvantages | When to use |
|---|---|---|---|
| Network Drive | • Simple implementation • No message queue needed |
• Dependency on network file system | When servers are on the same network and shared folder access can be configured |
| Utilities on Server A | • Software A controls entire process • Software B only receives result |
• Load on Server A | When Server A is powerful and Server B is only for result display |
| Utilities on Server B | • Offloads Server A | • Software B must be able to run utilities | When Server B is closer to laboratory (where data is generated) |
| Separate Server V | • Maximum flexibility and scalability | • Requires additional Software V application | When utilities must be isolated or when many Server A/B instances exist |
Start with a simple scenario (network drive or utilities on one of existing servers).
Move to separate Server V only when scaling or isolation is required.
Critical Requirements
Always use the format
input-{utilityName}-{batchId}.csv and output-{utilityName}-{batchId}.json.This prevents conflicts when processing a single batch with multiple utilities simultaneously.
The utility always returns
Exit Code = 0 on successful launch (even if data validation fails).Check the
ErrorMessage field in output.json to determine data validation errors.
Utilities work quickly (usually < 1 second), but for reliability set a 30-60 second timeout for execution.
Utilities do not require administrator rights and run locally. No data is transmitted to the internet.