forked from stackimpact/stackimpact-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMessageQueue.java
More file actions
156 lines (119 loc) · 3.7 KB
/
MessageQueue.java
File metadata and controls
156 lines (119 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package com.stackimpact.agent;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
public class MessageQueue {
public static class Message {
public String topic;
public Object content;
public long addedAt;
}
public final static long FLUSH_INTERVAL = 5 * 1000;
public final static long MESSAGE_TTL = 10 * 60 * 1000;
private Agent agent;
private List<Message> queue = (List<Message>)Collections.synchronizedList(new ArrayList<Message>());
private Timer flushTimer;
private long backoffSeconds;
private long lastFlushTS;
public MessageQueue(Agent agent) {
this.agent = agent;
}
public List<Message> getQueue() {
return queue;
}
public long getBackoffSeconds() {
return backoffSeconds;
}
public void reset() {
backoffSeconds = 0;
lastFlushTS = AgentUtils.millis();
queue.clear();
}
public void start() {
reset();
flushTimer = new Timer();
flushTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
flush();
}
catch(Exception ex) {
agent.logException(ex);
}
}
}, FLUSH_INTERVAL, FLUSH_INTERVAL);
}
public void stop() {
if (flushTimer != null) {
flushTimer.cancel();
}
}
public void add(String topic, Object content) {
Message message = new Message();
message.topic = topic;
message.content = content;
message.addedAt = AgentUtils.millis();
queue.add(message);
}
public void flush() {
long now = AgentUtils.millis();
if (!agent.isAutoProfilingMode() && lastFlushTS > now - FLUSH_INTERVAL) {
return;
}
if (queue.size() == 0) {
return;
}
// flush only if backoff time is elapsed
if (lastFlushTS + backoffSeconds * 1000 > now) {
return;
}
// expire old messages
synchronized(queue) {
Iterator<Message> iter = queue.iterator();
while (iter.hasNext()) {
Message message = iter.next();
if (message.addedAt < now - MESSAGE_TTL) {
iter.remove();
}
}
}
if (queue.size() == 0) {
return;
}
// read queue
List<Message> outgoing = (List<Message>)Collections.synchronizedList(new ArrayList<Message>(queue));
queue.clear();
Map payloadObj = new HashMap();
List messagesArr = new ArrayList();
payloadObj.put("messages", messagesArr);
for (Message message : outgoing) {
HashMap messageObj = new HashMap();
messageObj.put("topic", message.topic);
messageObj.put("content", message.content);
messagesArr.add(messageObj);
}
lastFlushTS = now;
try {
agent.getAPIRequest().post("upload", payloadObj);
backoffSeconds = 0;
}
catch(Exception ex) {
agent.logError("Error uploading messages to the dashboard, backing off next upload");
agent.logException(ex);
queue.addAll(0, outgoing);
// increase backoff up to 1 minute
if (backoffSeconds == 0) {
backoffSeconds = 10;
}
else if (backoffSeconds * 2 < 60) {
backoffSeconds *= 2;
}
}
}
}