Search in sources :

Example 51 with MessageGroup

use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.

the class JdbcMessageStoreTests method testCompletedNotExpiredGroupINT3037.

@Test
public void testCompletedNotExpiredGroupINT3037() throws Exception {
    /*
		 * based on the aggregator scenario as follows;
		 *
		 * send three messages in
		 * 1 of 2
		 * 2 of 2
		 * 2 of 2 (last again)
		 *
		 * expected behavior is that the LAST message (2 of 2 repeat) should be on the discard channel
		 * (discard behavior performed by the AbstractCorrelatingMessageHandler.handleMessageInternal)
		 */
    final JdbcMessageStore messageStore = new JdbcMessageStore(dataSource);
    // init
    String groupId = "group";
    // build the messages
    Message<?> oneOfTwo = MessageBuilder.withPayload("hello").setSequenceNumber(1).setSequenceSize(2).setCorrelationId(groupId).build();
    Message<?> twoOfTwo = MessageBuilder.withPayload("world").setSequenceNumber(2).setSequenceSize(2).setCorrelationId(groupId).build();
    // add to the messageStore
    messageStore.addMessagesToGroup(groupId, oneOfTwo, twoOfTwo);
    // check that 2 messages are there
    assertTrue(messageStore.getMessageGroupCount() == 1);
    assertTrue(messageStore.getMessageCount() == 2);
    // retrieve the group (like in the aggregator)
    MessageGroup messageGroup = messageStore.getMessageGroup(groupId);
    // 'complete' the group
    messageStore.completeGroup(messageGroup.getGroupId());
    // now clear the messages
    for (Message<?> message : messageGroup.getMessages()) {
        messageStore.removeMessagesFromGroup(groupId, message);
    }
    // end for
    // 'add' the other message --> emulated by getting the messageGroup
    messageGroup = messageStore.getMessageGroup(groupId);
    // should be marked 'complete' --> old behavior it would not
    assertTrue(messageGroup.isComplete());
}
Also used : MessageGroup(org.springframework.integration.store.MessageGroup) Test(org.junit.Test)

Example 52 with MessageGroup

use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.

the class AbstractCorrelatingMessageHandler method processForceRelease.

private void processForceRelease(Object groupId) {
    MessageGroup messageGroup = this.messageStore.getMessageGroup(groupId);
    this.forceReleaseProcessor.processMessageGroup(messageGroup);
}
Also used : MessageGroup(org.springframework.integration.store.MessageGroup) SimpleMessageGroup(org.springframework.integration.store.SimpleMessageGroup)

Example 53 with MessageGroup

use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.

the class AbstractCorrelatingMessageHandler method removeEmptyGroupAfterTimeout.

private void removeEmptyGroupAfterTimeout(MessageGroup messageGroup, long timeout) {
    Object groupId = messageGroup.getGroupId();
    UUID groupUuid = UUIDConverter.getUUID(groupId);
    ScheduledFuture<?> scheduledFuture = getTaskScheduler().schedule(() -> {
        Lock lock = this.lockRegistry.obtain(groupUuid.toString());
        try {
            lock.lockInterruptibly();
            try {
                this.expireGroupScheduledFutures.remove(groupUuid);
                /*
							 * Obtain a fresh state for group from the MessageStore,
							 * since it could be changed while we have waited for lock.
							 */
                MessageGroup groupNow = this.messageStore.getMessageGroup(groupUuid);
                boolean removeGroup = groupNow.size() == 0 && groupNow.getLastModified() <= (System.currentTimeMillis() - this.minimumTimeoutForEmptyGroups);
                if (removeGroup) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Removing empty group: " + groupUuid);
                    }
                    remove(messageGroup);
                }
            } finally {
                lock.unlock();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Thread was interrupted while trying to obtain lock." + "Rescheduling empty MessageGroup [ " + groupId + "] for removal.");
            }
            removeEmptyGroupAfterTimeout(messageGroup, timeout);
        }
    }, new Date(System.currentTimeMillis() + timeout));
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Schedule empty MessageGroup [ " + groupId + "] for removal.");
    }
    this.expireGroupScheduledFutures.put(groupUuid, scheduledFuture);
}
Also used : MessageGroup(org.springframework.integration.store.MessageGroup) SimpleMessageGroup(org.springframework.integration.store.SimpleMessageGroup) UUID(java.util.UUID) Date(java.util.Date) Lock(java.util.concurrent.locks.Lock)

Example 54 with MessageGroup

use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.

the class AbstractCorrelatingMessageHandlerTests method testReaperDoesntReapAProcessingGroup.

// INT-2751
@Test
public void testReaperDoesntReapAProcessingGroup() throws Exception {
    final MessageGroupStore groupStore = new SimpleMessageStore();
    final CountDownLatch waitForSendLatch = new CountDownLatch(1);
    final CountDownLatch waitReapStartLatch = new CountDownLatch(1);
    final CountDownLatch waitReapCompleteLatch = new CountDownLatch(1);
    AbstractCorrelatingMessageHandler handler = new AbstractCorrelatingMessageHandler(group -> group, groupStore) {

        @Override
        protected void afterRelease(MessageGroup group, Collection<Message<?>> completedMessages) {
        }
    };
    handler.setReleasePartialSequences(true);
    /*
		 * Runs "reap" when group 'bar' is in completion
		 */
    ExecutorService exec = Executors.newSingleThreadExecutor();
    exec.execute(() -> {
        try {
            waitReapStartLatch.await(10, TimeUnit.SECONDS);
        } catch (InterruptedException e1) {
            Thread.currentThread().interrupt();
        }
        waitForSendLatch.countDown();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e2) {
            Thread.currentThread().interrupt();
        }
        groupStore.expireMessageGroups(50);
        waitReapCompleteLatch.countDown();
    });
    final List<Message<?>> outputMessages = new ArrayList<Message<?>>();
    handler.setOutputChannel((message, timeout) -> {
        /*
			 * Executes when group 'bar' completes normally
			 */
        outputMessages.add(message);
        // wake reaper
        waitReapStartLatch.countDown();
        try {
            waitForSendLatch.await(10, TimeUnit.SECONDS);
            // wait a little longer for reaper to grab groups
            Thread.sleep(2000);
            // simulate tx commit
            groupStore.removeMessageGroup("bar");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return true;
    });
    handler.setReleaseStrategy(group -> group.size() == 2);
    QueueChannel discards = new QueueChannel();
    handler.setDiscardChannel(discards);
    handler.setSendPartialResultOnExpiry(true);
    Message<String> message = MessageBuilder.withPayload("foo").setCorrelationId("qux").build();
    // partial group that will be reaped
    handler.handleMessage(message);
    message = MessageBuilder.withPayload("foo").setCorrelationId("bar").build();
    // full group that should not be reaped
    handler.handleMessage(message);
    message = MessageBuilder.withPayload("baz").setCorrelationId("bar").build();
    handler.handleMessage(message);
    assertTrue(waitReapCompleteLatch.await(10, TimeUnit.SECONDS));
    // Before INT-2751 we got bar + bar + qux
    // bar + qux
    assertEquals(2, outputMessages.size());
    // normal release
    // 'bar'
    assertEquals(2, ((MessageGroup) outputMessages.get(0).getPayload()).size());
    // reaper release
    // 'qux'
    assertEquals(1, ((MessageGroup) outputMessages.get(1).getPayload()).size());
    assertNull(discards.receive(0));
    exec.shutdownNow();
}
Also used : MessageGroupStore(org.springframework.integration.store.MessageGroupStore) SimpleMessageStore(org.springframework.integration.store.SimpleMessageStore) Message(org.springframework.messaging.Message) GenericMessage(org.springframework.messaging.support.GenericMessage) QueueChannel(org.springframework.integration.channel.QueueChannel) MessageGroup(org.springframework.integration.store.MessageGroup) SimpleMessageGroup(org.springframework.integration.store.SimpleMessageGroup) ArrayList(java.util.ArrayList) CountDownLatch(java.util.concurrent.CountDownLatch) ExecutorService(java.util.concurrent.ExecutorService) Collection(java.util.Collection) Test(org.junit.Test)

Example 55 with MessageGroup

use of org.springframework.integration.store.MessageGroup in project spring-integration by spring-projects.

the class AbstractCorrelatingMessageHandlerTests method testDontReapIfAlreadyCompleteAfterRefetch.

/*
	 * INT-3216 - Verifies the complete early exit is taken after a refresh.
	 */
@Test
public void testDontReapIfAlreadyCompleteAfterRefetch() throws Exception {
    MessageGroupProcessor mgp = new DefaultAggregatingMessageGroupProcessor();
    AggregatingMessageHandler handler = new AggregatingMessageHandler(mgp);
    handler.setReleaseStrategy(group -> true);
    QueueChannel outputChannel = new QueueChannel();
    handler.setOutputChannel(outputChannel);
    MessageGroupStore mgs = TestUtils.getPropertyValue(handler, "messageStore", MessageGroupStore.class);
    mgs.addMessagesToGroup("foo", new GenericMessage<String>("foo"));
    MessageGroup group = new SimpleMessageGroup(mgs.getMessageGroup("foo"));
    mgs.completeGroup("foo");
    mgs = spy(mgs);
    new DirectFieldAccessor(handler).setPropertyValue("messageStore", mgs);
    Method forceComplete = AbstractCorrelatingMessageHandler.class.getDeclaredMethod("forceComplete", MessageGroup.class);
    forceComplete.setAccessible(true);
    MessageGroup groupInStore = (MessageGroup) TestUtils.getPropertyValue(mgs, "groupIdToMessageGroup", Map.class).get("foo");
    assertTrue(groupInStore.isComplete());
    assertFalse(group.isComplete());
    new DirectFieldAccessor(group).setPropertyValue("lastModified", groupInStore.getLastModified());
    forceComplete.invoke(handler, group);
    verify(mgs).getMessageGroup("foo");
    assertNull(outputChannel.receive(0));
}
Also used : MessageGroupStore(org.springframework.integration.store.MessageGroupStore) QueueChannel(org.springframework.integration.channel.QueueChannel) DirectFieldAccessor(org.springframework.beans.DirectFieldAccessor) MessageGroup(org.springframework.integration.store.MessageGroup) SimpleMessageGroup(org.springframework.integration.store.SimpleMessageGroup) Method(java.lang.reflect.Method) SimpleMessageGroup(org.springframework.integration.store.SimpleMessageGroup) Test(org.junit.Test)

Aggregations

MessageGroup (org.springframework.integration.store.MessageGroup)98 Test (org.junit.Test)79 SimpleMessageGroup (org.springframework.integration.store.SimpleMessageGroup)54 GenericMessage (org.springframework.messaging.support.GenericMessage)36 MessageGroupStore (org.springframework.integration.store.MessageGroupStore)25 Message (org.springframework.messaging.Message)20 ArrayList (java.util.ArrayList)19 RedisAvailable (org.springframework.integration.redis.rules.RedisAvailable)15 RedisConnectionFactory (org.springframework.data.redis.connection.RedisConnectionFactory)14 MongoDbAvailable (org.springframework.integration.mongodb.rules.MongoDbAvailable)13 AbstractBatchingMessageGroupStore (org.springframework.integration.store.AbstractBatchingMessageGroupStore)13 MongoClient (com.mongodb.MongoClient)12 SimpleMongoDbFactory (org.springframework.data.mongodb.core.SimpleMongoDbFactory)12 Transactional (org.springframework.transaction.annotation.Transactional)10 LinkedList (java.util.LinkedList)8 List (java.util.List)7 Matchers.containsString (org.hamcrest.Matchers.containsString)7 UUID (java.util.UUID)6 DirectFieldAccessor (org.springframework.beans.DirectFieldAccessor)6 HashMap (java.util.HashMap)5