Oracle AQ с ODP.Net. Автоматически отключать при подключении
Я использую Oracle ODP.Net для постановки и снятия с очереди.
Процесс A: постановка в очередь Процесс B: постановка в очередь с событием MessageAvailable
Если процессы A и B запущены, проблем нет. В "Процессе Б" событие всегда запускается.
Но если "Процесс B" выключен, а "Процесс А" включен, то, когда "Процесс В" перезапускается, очереди, вставленные во время отключения, теряются.
Есть ли возможность для запуска события для всех очередей, вставленных в прошлом?
Большое спасибо
2 ответа
Кажется, есть два подхода к решению этой проблемы:
- Вызовите метод Listen() класса OracleAQQueue (после регистрации уведомления о сообщении), чтобы забрать "осиротевшие" сообщения, находящиеся в очереди. Обратите внимание, что Listen() блокируется до тех пор, пока не будет получено сообщение или не истечет время ожидания. Таким образом, вы хотите указать (короткий) тайм-аут, чтобы вернуться к потоку обработки, если в очереди нет сообщений.
- Вызовите метод Dequeue() и перехватите сообщение об ошибке Oracle 25228 (сообщение не доступно для удаления из очереди). Смотрите следующую ветку на форумах поддержки Oracle: https://forums.oracle.com/forums/thread.jspa?threadID=2186496.
Я почесал голову на эту тему. Если вам все еще нужно "вручную" проверять наличие новых сообщений, в чем преимущество использования обратного вызова события MessageAvaiable? Один из способов, который я обдумал, - обернуть метод Listen() в асинхронный вызов, чтобы вызывающая сторона не блокировала поток (до тех пор, пока не будет получено сообщение или не истечет время ожидания). Я обернул Listen() и Dequeue() в собственный метод Receive() и создал свой собственный обработчик событий MessageReceived, чтобы передать детали сообщения в вызывающий поток. Кажется несколько избыточным, поскольку ODP.NET обеспечивает обратный вызов "из коробки", но мне не нужно иметь дело с описанной вами проблемой (или писать код для "ручного" тестирования "осиротевших" сообщений).
Любые комментарии / мысли о подходе приветствуются.
Я тоже смотрел на это и закончил тем, что делал что-то похожее на Грега. Я не использовал метод Listen(), так как не думаю, что он предлагает мне что-то сверх простой Dequeue() - Listen() кажется полезным, когда вы хотите слушать от имени нескольких потребителей, которые в Мой экземпляр не имеет значения (см. Oracle Docs).
Итак, в моем "Процессе Б" я сначала регистрируюсь на получение уведомлений, прежде чем инициировать процесс опроса для проверки любых существующих сообщений. Он не слушает (), он просто вызывает Dequeue () в управляемом цикле с установленным периодом ожидания в несколько секунд. Если в процессе опроса обнаружен таймаут Oracle, период ожидания истек, и опрос останавливается. Возможно, мне придется рассмотреть вопрос об истечении времени ожидания, если период ожидания еще не истек (хотя не уверен на 100%, если это произойдет).
Я заметил, что любые сообщения, которые ставятся в очередь во время опроса, будут вызывать метод уведомления о сообщениях, но к тому времени, когда это подключается и пытается получить сообщение, процесс опроса, кажется, всегда его принимает. Поэтому внутри метода уведомления о сообщении я фиксирую и игнорирую любые исключения OracleException с номером 25263 (no message in queue <...> with message ID <...>
).