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();
}
}
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;
}
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));
});
}
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;
}
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();
}
Aggregations