|
16 | 16 |
|
17 | 17 | package io.sermant.mq.grayscale.rocketmq.interceptor; |
18 | 18 |
|
| 19 | +import io.sermant.core.common.LoggerFactory; |
19 | 20 | import io.sermant.core.plugin.agent.entity.ExecuteContext; |
20 | 21 | import io.sermant.core.utils.StringUtils; |
21 | 22 | import io.sermant.mq.grayscale.rocketmq.service.RocketMqConsumerGroupAutoCheck; |
|
26 | 27 | import org.apache.rocketmq.client.impl.consumer.RebalanceImpl; |
27 | 28 | import org.apache.rocketmq.client.impl.factory.MQClientInstance; |
28 | 29 |
|
| 30 | +import java.util.ArrayList; |
| 31 | +import java.util.Collection; |
| 32 | +import java.util.List; |
| 33 | +import java.util.Locale; |
29 | 34 | import java.util.concurrent.ConcurrentMap; |
| 35 | +import java.util.logging.Logger; |
30 | 36 |
|
31 | 37 | /** |
32 | 38 | * TAG/SQL92 query message statement interceptor |
|
35 | 41 | * @since 2024-05-27 |
36 | 42 | **/ |
37 | 43 | public class RocketMqSchedulerRebuildSubscriptionInterceptor extends RocketMqAbstractInterceptor { |
38 | | - private final Object lock = new Object(); |
| 44 | + private static final Logger LOGGER = LoggerFactory.getLogger(); |
| 45 | + |
| 46 | + private static final String RETRY_TOPIC_FLAG = "%RETRY%"; |
39 | 47 |
|
40 | 48 | @Override |
41 | 49 | public ExecuteContext doAfter(ExecuteContext context) throws Exception { |
42 | | - ConcurrentMap<String, Object> map = (ConcurrentMap<String, Object>) context.getResult(); |
| 50 | + ConcurrentMap<String, Object> subscriptionInner = (ConcurrentMap<String, Object>) context.getResult(); |
43 | 51 | RebalanceImpl balance = (RebalanceImpl) context.getObject(); |
44 | 52 | if (balance.getConsumerGroup() == null) { |
45 | 53 | return context; |
46 | 54 | } |
47 | | - for (Object subscriptionData : map.values()) { |
| 55 | + List<Object> retryTopicSubscriptions = new ArrayList<>(); |
| 56 | + List<Object> originTopicSubscriptions = new ArrayList<>(); |
| 57 | + buildTopicSubscriptions(subscriptionInner, retryTopicSubscriptions, originTopicSubscriptions); |
| 58 | + Object changedOriginSubscription = null; |
| 59 | + for (Object subscriptionData : originTopicSubscriptions) { |
48 | 60 | if (RocketMqSubscriptionDataUtils |
49 | 61 | .isExpressionTypeInaccurate(RocketMqReflectUtils.getExpressionType(subscriptionData))) { |
50 | 62 | continue; |
51 | 63 | } |
52 | | - buildSql92SubscriptionData(subscriptionData, balance); |
| 64 | + String topic = RocketMqReflectUtils.getTopic(subscriptionData); |
| 65 | + if (!RocketMqSubscriptionDataUtils.getGrayTagChangeFlag(topic, balance)) { |
| 66 | + continue; |
| 67 | + } |
| 68 | + buildSql92SubscriptionData(subscriptionData, balance, topic); |
| 69 | + |
| 70 | + // sql92 expression is associated only with the consumer group. Therefore, |
| 71 | + // using any of the changed subscription build retry-topic sql92 expression. |
| 72 | + changedOriginSubscription = subscriptionData; |
| 73 | + } |
| 74 | + if (changedOriginSubscription != null) { |
| 75 | + // update %RETRY%+GROUP substring with sql92 |
| 76 | + updateRetrySubscriptionData(changedOriginSubscription, retryTopicSubscriptions); |
53 | 77 | } |
54 | 78 | return context; |
55 | 79 | } |
56 | 80 |
|
57 | | - private void buildSql92SubscriptionData(Object subscriptionData, RebalanceImpl balance) { |
58 | | - synchronized (lock) { |
59 | | - String topic = RocketMqReflectUtils.getTopic(subscriptionData); |
60 | | - if (!RocketMqSubscriptionDataUtils.getGrayTagChangeFlag(topic, balance)) { |
61 | | - return; |
62 | | - } |
63 | | - String consumerGroup = balance.getConsumerGroup(); |
64 | | - MQClientInstance instance = balance.getmQClientFactory(); |
65 | | - if (StringUtils.isEmpty(RocketMqGrayscaleConfigUtils.getGrayGroupTag())) { |
66 | | - RocketMqConsumerGroupAutoCheck.setMqClientInstance(topic, consumerGroup, instance); |
67 | | - RocketMqConsumerGroupAutoCheck.syncUpdateCacheGrayTags(); |
68 | | - RocketMqConsumerGroupAutoCheck.startSchedulerCheckGroupTask(); |
| 81 | + private void buildTopicSubscriptions(ConcurrentMap<String, Object> subscriptionInner, |
| 82 | + List<Object> retryTopicSubscriptions, List<Object> originTopicSubscriptions) { |
| 83 | + // If one consumer subscribe many topic when create, subscriptionInner data structure is: |
| 84 | + // many origin topic subscriptionData, as topic1:subscriptionData1 topic2:subscriptionData2 |
| 85 | + // Currently, there is only one retry topic subscriptionData, because the retry topic is associated with |
| 86 | + // consumer group, so that one consumer group has only one rebalancing task, still using array storage |
| 87 | + // for convenience |
| 88 | + for (Object subscriptionData : subscriptionInner.values()) { |
| 89 | + String tempTopic = RocketMqReflectUtils.getTopic(subscriptionData); |
| 90 | + if (tempTopic.contains(RETRY_TOPIC_FLAG)) { |
| 91 | + retryTopicSubscriptions.add(subscriptionData); |
| 92 | + } else { |
| 93 | + originTopicSubscriptions.add(subscriptionData); |
69 | 94 | } |
70 | | - String namesrvAddr = balance.getmQClientFactory().getClientConfig().getNamesrvAddr(); |
71 | | - resetsSql92SubscriptionData(topic, consumerGroup, subscriptionData, namesrvAddr); |
| 95 | + } |
| 96 | + } |
72 | 97 |
|
73 | | - // update change flag when finished build substr |
74 | | - RocketMqSubscriptionDataUtils.resetTagChangeMap(namesrvAddr, topic, consumerGroup, false); |
| 98 | + private void updateRetrySubscriptionData(Object subscriptionData, Collection<Object> retryTopicSubscriptions) { |
| 99 | + for (Object subData : retryTopicSubscriptions) { |
| 100 | + RocketMqReflectUtils.getTagsSet(subData).clear(); |
| 101 | + RocketMqReflectUtils.getCodeSet(subData).clear(); |
| 102 | + RocketMqReflectUtils.setSubscriptionData(subData, "setExpressionType", |
| 103 | + new Class[]{String.class}, new Object[]{"SQL92"}); |
| 104 | + RocketMqReflectUtils.setSubscriptionData(subData, "setSubVersion", |
| 105 | + new Class[]{long.class}, new Object[]{System.currentTimeMillis()}); |
| 106 | + String originSubData = RocketMqReflectUtils.getSubString(subData); |
| 107 | + String sqlSubstr = RocketMqReflectUtils.getSubString(subscriptionData); |
| 108 | + RocketMqReflectUtils.setSubscriptionData(subData, "setSubString", |
| 109 | + new Class[]{String.class}, new Object[]{sqlSubstr}); |
| 110 | + String originTopic = RocketMqReflectUtils.getTopic(subscriptionData); |
| 111 | + String retryTopic = RocketMqReflectUtils.getTopic(subData); |
| 112 | + LOGGER.warning(String.format(Locale.ENGLISH, "update retry topic [%s] SQL92 expression, " |
| 113 | + + "originTopic: [%s], originSubStr: [%s], newSubStr: [%s]", retryTopic, originTopic, |
| 114 | + originSubData, sqlSubstr)); |
75 | 115 | } |
76 | 116 | } |
77 | 117 |
|
| 118 | + private void buildSql92SubscriptionData(Object subscriptionData, RebalanceImpl balance, String topic) { |
| 119 | + String consumerGroup = balance.getConsumerGroup(); |
| 120 | + MQClientInstance instance = balance.getmQClientFactory(); |
| 121 | + if (StringUtils.isEmpty(RocketMqGrayscaleConfigUtils.getGrayGroupTag())) { |
| 122 | + RocketMqConsumerGroupAutoCheck.setMqClientInstance(topic, consumerGroup, instance); |
| 123 | + RocketMqConsumerGroupAutoCheck.syncUpdateCacheGrayTags(); |
| 124 | + RocketMqConsumerGroupAutoCheck.startSchedulerCheckGroupTask(); |
| 125 | + } |
| 126 | + String namesrvAddr = balance.getmQClientFactory().getClientConfig().getNamesrvAddr(); |
| 127 | + resetsSql92SubscriptionData(topic, consumerGroup, subscriptionData, namesrvAddr); |
| 128 | + |
| 129 | + // update change flag when finished build substr |
| 130 | + RocketMqSubscriptionDataUtils.resetTagChangeMap(namesrvAddr, topic, consumerGroup, false); |
| 131 | + } |
| 132 | + |
78 | 133 | private void resetsSql92SubscriptionData(String topic, String consumerGroup, Object subscriptionData, |
79 | 134 | String namesrvAddr) { |
80 | 135 | String subscribeScope = RocketMqSubscriptionDataUtils.buildSubscribeScope(topic, consumerGroup, |
|
0 commit comments