Search in sources :

Example 16 with ReleaseMessage

use of com.ctrip.framework.apollo.biz.entity.ReleaseMessage in project apollo by ctripcorp.

the class ReleaseMessageServiceWithCache method mergeReleaseMessage.

private synchronized void mergeReleaseMessage(ReleaseMessage releaseMessage) {
    ReleaseMessage old = releaseMessageCache.get(releaseMessage.getMessage());
    if (old == null || releaseMessage.getId() > old.getId()) {
        releaseMessageCache.put(releaseMessage.getMessage(), releaseMessage);
        maxIdScanned = releaseMessage.getId();
    }
}
Also used : ReleaseMessage(com.ctrip.framework.apollo.biz.entity.ReleaseMessage)

Example 17 with ReleaseMessage

use of com.ctrip.framework.apollo.biz.entity.ReleaseMessage in project apollo by ctripcorp.

the class NotificationControllerV2 method getApolloConfigNotifications.

private List<ApolloConfigNotification> getApolloConfigNotifications(Set<String> namespaces, Map<String, Long> clientSideNotifications, Multimap<String, String> watchedKeysMap, List<ReleaseMessage> latestReleaseMessages) {
    List<ApolloConfigNotification> newNotifications = Lists.newArrayList();
    if (!CollectionUtils.isEmpty(latestReleaseMessages)) {
        Map<String, Long> latestNotifications = Maps.newHashMap();
        for (ReleaseMessage releaseMessage : latestReleaseMessages) {
            latestNotifications.put(releaseMessage.getMessage(), releaseMessage.getId());
        }
        for (String namespace : namespaces) {
            long clientSideId = clientSideNotifications.get(namespace);
            long latestId = ConfigConsts.NOTIFICATION_ID_PLACEHOLDER;
            Collection<String> namespaceWatchedKeys = watchedKeysMap.get(namespace);
            for (String namespaceWatchedKey : namespaceWatchedKeys) {
                long namespaceNotificationId = latestNotifications.getOrDefault(namespaceWatchedKey, ConfigConsts.NOTIFICATION_ID_PLACEHOLDER);
                if (namespaceNotificationId > latestId) {
                    latestId = namespaceNotificationId;
                }
            }
            if (latestId > clientSideId) {
                ApolloConfigNotification notification = new ApolloConfigNotification(namespace, latestId);
                namespaceWatchedKeys.stream().filter(latestNotifications::containsKey).forEach(namespaceWatchedKey -> notification.addMessage(namespaceWatchedKey, latestNotifications.get(namespaceWatchedKey)));
                newNotifications.add(notification);
            }
        }
    }
    return newNotifications;
}
Also used : ReleaseMessage(com.ctrip.framework.apollo.biz.entity.ReleaseMessage) ApolloConfigNotification(com.ctrip.framework.apollo.core.dto.ApolloConfigNotification)

Example 18 with ReleaseMessage

use of com.ctrip.framework.apollo.biz.entity.ReleaseMessage in project apollo by ctripcorp.

the class ReleaseMessageScannerTest method testScanMessageWithGapAndNotifyMessageListener.

@Test
public void testScanMessageWithGapAndNotifyMessageListener() throws Exception {
    String someMessage = "someMessage";
    long someId = 1;
    ReleaseMessage someReleaseMessage = assembleReleaseMessage(someId, someMessage);
    String someMissingMessage = "someMissingMessage";
    long someMissingId = 2;
    ReleaseMessage someMissingReleaseMessage = assembleReleaseMessage(someMissingId, someMissingMessage);
    String anotherMessage = "anotherMessage";
    long anotherId = 3;
    ReleaseMessage anotherReleaseMessage = assembleReleaseMessage(anotherId, anotherMessage);
    String anotherMissingMessage = "anotherMissingMessage";
    long anotherMissingId = 4;
    ReleaseMessage anotherMissingReleaseMessage = assembleReleaseMessage(anotherMissingId, anotherMissingMessage);
    long someRolledBackId = 5;
    String yetAnotherMessage = "yetAnotherMessage";
    long yetAnotherId = 6;
    ReleaseMessage yetAnotherReleaseMessage = assembleReleaseMessage(yetAnotherId, yetAnotherMessage);
    ArrayList<ReleaseMessage> receivedMessage = Lists.newArrayList();
    SettableFuture<ReleaseMessage> someListenerFuture = SettableFuture.create();
    ReleaseMessageListener someListener = (message, channel) -> receivedMessage.add(message);
    releaseMessageScanner.addMessageListener(someListener);
    when(releaseMessageRepository.findFirst500ByIdGreaterThanOrderByIdAsc(0L)).thenReturn(Lists.newArrayList(someReleaseMessage));
    await().untilAsserted(() -> {
        assertEquals(1, receivedMessage.size());
        assertSame(someReleaseMessage, receivedMessage.get(0));
    });
    when(releaseMessageRepository.findFirst500ByIdGreaterThanOrderByIdAsc(someId)).thenReturn(Lists.newArrayList(anotherReleaseMessage));
    await().untilAsserted(() -> {
        assertEquals(2, receivedMessage.size());
        assertSame(someReleaseMessage, receivedMessage.get(0));
        assertSame(anotherReleaseMessage, receivedMessage.get(1));
    });
    when(releaseMessageRepository.findAllById(Sets.newHashSet(someMissingId))).thenReturn(Lists.newArrayList(someMissingReleaseMessage));
    await().untilAsserted(() -> {
        assertEquals(3, receivedMessage.size());
        assertSame(someReleaseMessage, receivedMessage.get(0));
        assertSame(anotherReleaseMessage, receivedMessage.get(1));
        assertSame(someMissingReleaseMessage, receivedMessage.get(2));
    });
    when(releaseMessageRepository.findFirst500ByIdGreaterThanOrderByIdAsc(anotherId)).thenReturn(Lists.newArrayList(yetAnotherReleaseMessage));
    await().untilAsserted(() -> {
        assertEquals(4, receivedMessage.size());
        assertSame(someReleaseMessage, receivedMessage.get(0));
        assertSame(anotherReleaseMessage, receivedMessage.get(1));
        assertSame(someMissingReleaseMessage, receivedMessage.get(2));
        assertSame(yetAnotherReleaseMessage, receivedMessage.get(3));
    });
    when(releaseMessageRepository.findAllById(Sets.newHashSet(anotherMissingId, someRolledBackId))).thenReturn(Lists.newArrayList(anotherMissingReleaseMessage));
    await().untilAsserted(() -> {
        assertEquals(5, receivedMessage.size());
        assertSame(someReleaseMessage, receivedMessage.get(0));
        assertSame(anotherReleaseMessage, receivedMessage.get(1));
        assertSame(someMissingReleaseMessage, receivedMessage.get(2));
        assertSame(yetAnotherReleaseMessage, receivedMessage.get(3));
        assertSame(anotherMissingReleaseMessage, receivedMessage.get(4));
    });
}
Also used : ReleaseMessageRepository(com.ctrip.framework.apollo.biz.repository.ReleaseMessageRepository) Awaitility.await(org.awaitility.Awaitility.await) Mock(org.mockito.Mock) ReleaseMessage(com.ctrip.framework.apollo.biz.entity.ReleaseMessage) ReflectionTestUtils(org.springframework.test.util.ReflectionTestUtils) Test(org.junit.Test) Mockito.when(org.mockito.Mockito.when) SettableFuture(com.google.common.util.concurrent.SettableFuture) Sets(com.google.common.collect.Sets) ArrayList(java.util.ArrayList) TimeUnit(java.util.concurrent.TimeUnit) Assert.assertSame(org.junit.Assert.assertSame) BizConfig(com.ctrip.framework.apollo.biz.config.BizConfig) Lists(com.google.common.collect.Lists) Awaitility(org.awaitility.Awaitility) AbstractUnitTest(com.ctrip.framework.apollo.biz.AbstractUnitTest) Assert.assertEquals(org.junit.Assert.assertEquals) Before(org.junit.Before) ReleaseMessage(com.ctrip.framework.apollo.biz.entity.ReleaseMessage) Test(org.junit.Test) AbstractUnitTest(com.ctrip.framework.apollo.biz.AbstractUnitTest)

Example 19 with ReleaseMessage

use of com.ctrip.framework.apollo.biz.entity.ReleaseMessage in project apollo by ctripcorp.

the class ReleaseMessageScannerTest method assembleReleaseMessage.

private ReleaseMessage assembleReleaseMessage(long id, String message) {
    ReleaseMessage releaseMessage = new ReleaseMessage();
    releaseMessage.setId(id);
    releaseMessage.setMessage(message);
    return releaseMessage;
}
Also used : ReleaseMessage(com.ctrip.framework.apollo.biz.entity.ReleaseMessage)

Example 20 with ReleaseMessage

use of com.ctrip.framework.apollo.biz.entity.ReleaseMessage in project apollo by ctripcorp.

the class NotificationControllerV2 method pollNotification.

@GetMapping
public DeferredResult<ResponseEntity<List<ApolloConfigNotification>>> pollNotification(@RequestParam(value = "appId") String appId, @RequestParam(value = "cluster") String cluster, @RequestParam(value = "notifications") String notificationsAsString, @RequestParam(value = "dataCenter", required = false) String dataCenter, @RequestParam(value = "ip", required = false) String clientIp) {
    List<ApolloConfigNotification> notifications = null;
    try {
        notifications = gson.fromJson(notificationsAsString, notificationsTypeReference);
    } catch (Throwable ex) {
        Tracer.logError(ex);
    }
    if (CollectionUtils.isEmpty(notifications)) {
        throw new BadRequestException("Invalid format of notifications: " + notificationsAsString);
    }
    Map<String, ApolloConfigNotification> filteredNotifications = filterNotifications(appId, notifications);
    if (CollectionUtils.isEmpty(filteredNotifications)) {
        throw new BadRequestException("Invalid format of notifications: " + notificationsAsString);
    }
    DeferredResultWrapper deferredResultWrapper = new DeferredResultWrapper(bizConfig.longPollingTimeoutInMilli());
    Set<String> namespaces = Sets.newHashSetWithExpectedSize(filteredNotifications.size());
    Map<String, Long> clientSideNotifications = Maps.newHashMapWithExpectedSize(filteredNotifications.size());
    for (Map.Entry<String, ApolloConfigNotification> notificationEntry : filteredNotifications.entrySet()) {
        String normalizedNamespace = notificationEntry.getKey();
        ApolloConfigNotification notification = notificationEntry.getValue();
        namespaces.add(normalizedNamespace);
        clientSideNotifications.put(normalizedNamespace, notification.getNotificationId());
        if (!Objects.equals(notification.getNamespaceName(), normalizedNamespace)) {
            deferredResultWrapper.recordNamespaceNameNormalizedResult(notification.getNamespaceName(), normalizedNamespace);
        }
    }
    Multimap<String, String> watchedKeysMap = watchKeysUtil.assembleAllWatchKeys(appId, cluster, namespaces, dataCenter);
    Set<String> watchedKeys = Sets.newHashSet(watchedKeysMap.values());
    /**
     * 1、set deferredResult before the check, for avoid more waiting
     * If the check before setting deferredResult,it may receive a notification the next time
     * when method handleMessage is executed between check and set deferredResult.
     */
    deferredResultWrapper.onTimeout(() -> logWatchedKeys(watchedKeys, "Apollo.LongPoll.TimeOutKeys"));
    deferredResultWrapper.onCompletion(() -> {
        // unregister all keys
        for (String key : watchedKeys) {
            deferredResults.remove(key, deferredResultWrapper);
        }
        logWatchedKeys(watchedKeys, "Apollo.LongPoll.CompletedKeys");
    });
    // register all keys
    for (String key : watchedKeys) {
        this.deferredResults.put(key, deferredResultWrapper);
    }
    logWatchedKeys(watchedKeys, "Apollo.LongPoll.RegisteredKeys");
    logger.debug("Listening {} from appId: {}, cluster: {}, namespace: {}, datacenter: {}", watchedKeys, appId, cluster, namespaces, dataCenter);
    /**
     * 2、check new release
     */
    List<ReleaseMessage> latestReleaseMessages = releaseMessageService.findLatestReleaseMessagesGroupByMessages(watchedKeys);
    /**
     * Manually close the entity manager.
     * Since for async request, Spring won't do so until the request is finished,
     * which is unacceptable since we are doing long polling - means the db connection would be hold
     * for a very long time
     */
    entityManagerUtil.closeEntityManager();
    List<ApolloConfigNotification> newNotifications = getApolloConfigNotifications(namespaces, clientSideNotifications, watchedKeysMap, latestReleaseMessages);
    if (!CollectionUtils.isEmpty(newNotifications)) {
        deferredResultWrapper.setResult(newNotifications);
    }
    return deferredResultWrapper.getResult();
}
Also used : ReleaseMessage(com.ctrip.framework.apollo.biz.entity.ReleaseMessage) BadRequestException(com.ctrip.framework.apollo.common.exception.BadRequestException) ApolloConfigNotification(com.ctrip.framework.apollo.core.dto.ApolloConfigNotification) DeferredResultWrapper(com.ctrip.framework.apollo.configservice.wrapper.DeferredResultWrapper) Map(java.util.Map) GetMapping(org.springframework.web.bind.annotation.GetMapping)

Aggregations

ReleaseMessage (com.ctrip.framework.apollo.biz.entity.ReleaseMessage)30 Test (org.junit.Test)16 ApolloConfigNotification (com.ctrip.framework.apollo.core.dto.ApolloConfigNotification)9 ResponseEntity (org.springframework.http.ResponseEntity)7 AbstractUnitTest (com.ctrip.framework.apollo.biz.AbstractUnitTest)3 Release (com.ctrip.framework.apollo.biz.entity.Release)3 ApolloNotificationMessages (com.ctrip.framework.apollo.core.dto.ApolloNotificationMessages)3 ArrayList (java.util.ArrayList)3 List (java.util.List)3 BizConfig (com.ctrip.framework.apollo.biz.config.BizConfig)2 ReleaseMessageRepository (com.ctrip.framework.apollo.biz.repository.ReleaseMessageRepository)2 Transaction (com.ctrip.framework.apollo.tracer.spi.Transaction)2 Lists (com.google.common.collect.Lists)2 Sets (com.google.common.collect.Sets)2 SettableFuture (com.google.common.util.concurrent.SettableFuture)2 TimeUnit (java.util.concurrent.TimeUnit)2 Awaitility (org.awaitility.Awaitility)2 Awaitility.await (org.awaitility.Awaitility.await)2 Assert.assertEquals (org.junit.Assert.assertEquals)2 Assert.assertSame (org.junit.Assert.assertSame)2