< Sergii Kostenko's blog

Встроенный сервер Jetty урезает ответы

06 августа 2019

Jetty сервер имеет множество вариантов конфигурации. Один из них, это OutputBufferSize

HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setOutputBufferSize(1024);

Если это свойство будет назначено значение меньше, чем ваш ответ - jetty просто будет обрезать обрезать последний.

Comments


WFLYEJB0054: Failed to marshal EJB parameters

05 августа 2019

Обычно ошибка WFLYEJB0054: Failed to marshal EJB parameters может быть вызвана по следующим причинам:

Кроме того, вы можете словить эту ошибку с абсолютно неожиданным сценарием и нечеткой трассировкой стека, когда ваш EJB выбрасывает несколько непроверяемых ошибок со стековой трассировкой, которая имеет объекты из точек выше.

Comments


SQL хак. Вставить, если не сущетсвует

24 июля 2019

Следующий SQL хак позволит вам выполнить условный INSERT для вашего запроса.

Например, давайте сделаем вставку, если записи ещё не будет существовать:

SQL:

INSERT INTO my_table (id, name)  
    SELECT 1, 'name' FROM dual  WHERE NOT EXISTS (SELECT 1 FROM my_table WHERE ID = 1);

Comments


JMS обнаружение дублирующихся сообщений с Wildfly

19 июля 2019

Для поддержки JMS спецификация Wildfly использует Apache ActiveMQ Artemis в подсистеме active-mq. Последнее предоставляет механизм фильтрации повторяющихся сообщений без изменения кода приложения.

Чтобы включить обнаружение повторяющихся сообщений, вам просто нужно установить специальное свойтсво сообщения с уникальным значением.

message.setStringProperty("_AMQ_DUPL_ID", uniqueId);

Итак, давайте посмотрим, как это работает на практике и создадим простой Message Driven Bean для использования сообщений:

@JMSDestinationDefinition(
        name = DuplicateJMSTestBean.DUPLICATE_QUEUE,
        interfaceName = "javax.jms.Queue"
)
@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = DuplicateJMSTestBean.DUPLICATE_QUEUE),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class DuplicateJMSTestBean implements MessageListener {

    public final static String DUPLICATE_QUEUE = "java:global/jms/duplicateTestQueue";

    @Override
    public void onMessage(Message msg) {
        System.out.println("Got new message.");
        MessageStorage.messages.add(msg);
        try {
            Thread.sleep(5_000l);
        } catch(Exception ignore) {}
        System.out.println("Message  successfully processed");
    }
}

И простую конечную точку JAX-RS для создания сообщений

@Path("/")
@Stateless
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class DuplicateTestEndpoint {

    @Inject
    private JMSContext context;
    @Resource(lookup = DuplicateJMSTestBean.DUPLICATE_QUEUE)
    private Queue queue;

    @GET
    @Path("/sendmessage")
    public Response sendMessage(@QueryParam("duplicate-id") String duplicateId) {
        try {
            ObjectMessage message = context.createObjectMessage();
            if (duplicateId == null) {
                context.createProducer().send(queue, message);
            } else {
                message.setStringProperty("_AMQ_DUPL_ID", duplicateId);
                context.createProducer().send(queue, message);
            }
            return Response.ok().entity("Message was sent.  Recieved " + MessageStorage.messages.size() + " messagges: " + MessageStorage.messages).build();
        } catch (Throwable e) {
            return Response.ok().entity("Error: " + e).build();
        }
    }
}

Теперь в случае, если мы отправим сообщение с тем же _AMQ_DUPL_ID без транзакции по адресу http://127.0.0.1:8080/jms-examples/sendmessage?duplicate-id=myuniqueid, мы получим в логах:

WARN [org.apache.activemq.artemis.core.server] (Thread-448 (ActiveMQ-server-org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl$5@e47887a)) AMQ222059: Duplicate message detected - message will not be routed. Message information:
CoreMessage[messageID=1505,durable=true,userID=3d27afde-a9fa-11e9-af5d-0242e352ec80,priority=4, timestamp=Fri Jul 19 10:53:04 EEST 2019,expiration=0, durable=true, address=jms.queue.jms-examples_jms-examples_jms-examples_java:global/jms/duplicateTestQueue,size=416,properties=TypedProperties[__AMQ_CID=38587489-a9fa-11e9-af5d-0242e352ec80,_AMQ_DUPL_ID=myuniqueid,_AMQ_ROUTING_TYPE=1]]@145077408

и сообщение НЕ будет потребляться потребителем. Если вы отправите сообщение в транзакции - вы получите Исключение при коммите.

Имейте в виду, что для хранения идентификаторов activemq, используют круговой кэш фиксированого размера.

/subsystem=messaging-activemq/server=default:read-attribute(name=id-cache-size)
{
    "outcome" => "success",
    "result" => 20000
}

Поэтому, это значение должно быть достаточно большими для того, чтобы избежать перезаписи. Также, вы можете сконфигурировать постоянный кэш или этого не делать (по умолчанию: true)

/subsystem=messaging-activemq/server=default:write-attribute(name=persist-id-cache,value=false)

Исходный код, доступен на GitHub

Comments


Jenkins. Приятно иметь плагины

05 июля 2019

Jenkins - главный инструмент автоматизации с открытым исходным кодом, который предоставляет множество плагинов для улучшения вашего CI.
Ниже приведены некоторые из них, которые, на мой взгляд, станут полезным для любого проекта.

1. Build Monitor Plugin - обеспечивает весьма ощутимое представление о статусе выбранных заданий Jenkins;

Build Monitor Plugin

2. Git Parameter Plugin - добавляет возможность выбирать ветки, теги или ревизии из git-репозитория, настроенного в проекте;

Git Parameter Plugin

3. HTML Publisher Plugin - публикует HTML-отчёты, которые ваш билд сгенерировал для работы и сборки страниц;

Git Parameter Plugin

Comments