Данная статья подготовлена Дмитрием Овчаренко, архитектором Департамента прикладных финансовых систем компании «Инфосистемы Джет»

Да будет унификация! Такое решение было принято при проектировании интеграционной архитектуры, связывающей CRM с другими внешними системами посредством шины на Oracle Service Bus. Помимо онлайн-интеграции на основе веб-сервисов, она принимает файлы, поступающие в систему, и вызывает веб-сервисы на стороне CRM, специально разработанные для каждого типа входящих данных.

Файл содержит множество записей, и по каждой требуется выполнить отдельный вызов сервиса на стороне CRM. Обработка файла производится в цикле по записям. На каждый вызов сервиса уходит по 5 секунд – это довольно много, но для выполнения поставленных требований вполне хватало. Процесс обработки вызова веб-сервиса в CRM предварительно проверяет запись на дубль, затем выполняет требуемую бизнес-логику и создает запись в БД.

Но «внезапности» могут возникнуть в непредвиденных моментах «шиномонтажа». На промышленных объемах данных в базе CRM стали появляться дубли. Мы выяснили, что источник может почему-то отправить большой файл повторно (сразу после того, как он будет подхвачен файловым proxy-сервисом и помещен в Stage-папку). Причем отставание между вызовами веб-сервисов, создающих дубли, настолько мало, что в момент второго вызова данные в первом еще не закоммичены, и проверка на стороне CRM не успевает срабатывать.


К черту унификацию! Решили реализовывать отдельный Statefull-сервис на Java, хранящий в памяти имена обрабатываемых в текущий момент файлов. При получении файла proxy-сервис на OSB вызывает Java-сервис, передает ему имя файла и узнает, обрабатывается ли он сейчас. В конце обработки файла (или в случае исключения) proxy-сервис сообщает Java-сервису о том, что он закончил обрабатывать файл с данным именем. Соответственно, это имя из списка текущих надо удалить. Обработка двух файлов с одинаковым именем недопустима по бизнес-требованиям. Рестарт сервера тоже не страшен, поскольку будет сброшен не только Java-процесс, но и обрабатываемый файл, если таковой окажется во время перезагрузки.

В общем случае в Oracle SOA Suite Service Bus 11g нет возможности установить блокировку на процесс с синхронизацией по какому-либо идентификатору – предлагается использовать подобный подход не только для ограничения запуска при повторном получении файла, но в принципе в любых случаях, передавая в Statefull-сервис нужный идентификатор.

При этом важно, чтобы в файловом обработчике на OSB был блок Catch верхнего уровня, для того чтобы удалить имя обрабатываемого файла из списка, даже если произошло исключение.

Код сервиса:

@WebService(serviceName = "TaskManager")
public class TaskManager {
    
    private static HashMap<String,String> map;
    public TaskManager() {
        super();
        map = new HashMap<String,String>();
    }

    @WebMethod
    @WebResult(name = "Result")
    public String addTask(@WebParam(name = "ProcessName") String name){        
        String result;       
        try{
            result = map.get(name); // Try to get name from map
        }catch (Exception e){       // if there is no such name
            result = null;          // we receive exception
        }        
        if (result == null){        // if there is no such name
            map.put(name, "Is running"); // we add name
            result = "Task added";            
        }
        else{
            result = "Task is running"; // else - inform caller
        }
        return result;
    }


    @WebMethod
    @WebResult(name = "Result")
    public String removeTask(@WebParam(name = "ProcessName") String name){
        String result;    
        try{
            result = map.get(name);
        }catch (Exception e){
            result = null;
        }
        if (result == null){
            result = "There is no task";            
        }
        else{
            map.remove(name);
            result = "Task removed";
        }
        return result;
    }
}


Данный метод очень простой, но, к сожалению, не будет действовать в кластерном варианте развертывания. Также желательно разворачивать его на OSB Managed-сервере WebLogic, чтобы при перезагрузке сбросились одновременно и процессы обработки OSB, и список текущих процессов. Если OSB серверы находятся в кластере, сервис должен быть развернут на отдельном Managed-сервере, и при перезагрузке об этом факте придется помнить.

В заключение. С такой защитой от повторных обработок решение работало больше года, однако ему на смену пришел новый механизм загрузки. Он реализован на Oracle SOA Suite, а обработка записей в нем выполняется параллельно. Но эту тему раскроет уже другая статья.

Мы будем рады вашим конструктивным комментариям.

Комментарии (0)