Skip to content

Commit 1d4f0f3

Browse files
authored
Extend SSE post-finish drain window (#99)
* Extend SSE drain grace period to 10s * Add delayed-result SSE regression test
1 parent 395e686 commit 1d4f0f3

3 files changed

Lines changed: 155 additions & 1 deletion

File tree

src/main/java/com/transloadit/sdk/EventsourceRunnable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import java.util.Iterator;
2323

2424
class EventsourceRunnable implements Runnable {
25-
private static final long FINISH_DRAIN_TIMEOUT_MS = 1500L;
25+
private static final long FINISH_DRAIN_TIMEOUT_MS = 10000L;
2626

2727
protected boolean assemblyFinished;
2828
protected AssemblyListener assemblyListener;
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package com.transloadit.sdk;
2+
3+
import com.launchdarkly.eventsource.ConnectStrategy;
4+
import com.launchdarkly.eventsource.ErrorStrategy;
5+
import com.launchdarkly.eventsource.RetryDelayStrategy;
6+
import com.sun.net.httpserver.HttpExchange;
7+
import com.sun.net.httpserver.HttpHandler;
8+
import com.sun.net.httpserver.HttpServer;
9+
import com.transloadit.sdk.response.AssemblyResponse;
10+
import org.json.JSONObject;
11+
import org.junit.jupiter.api.AfterEach;
12+
import org.junit.jupiter.api.BeforeEach;
13+
import org.junit.jupiter.api.Test;
14+
import org.mockito.Mockito;
15+
16+
import java.io.IOException;
17+
import java.io.OutputStream;
18+
import java.net.InetSocketAddress;
19+
import java.net.URI;
20+
import java.nio.charset.StandardCharsets;
21+
import java.util.concurrent.CountDownLatch;
22+
import java.util.concurrent.TimeUnit;
23+
import java.util.concurrent.atomic.AtomicReference;
24+
25+
import static org.junit.jupiter.api.Assertions.assertEquals;
26+
import static org.junit.jupiter.api.Assertions.assertTrue;
27+
import static org.mockito.ArgumentMatchers.anyString;
28+
import static org.mockito.Mockito.when;
29+
30+
class EventsourceRunnableDelayedResultTest {
31+
32+
private HttpServer server;
33+
private CountDownLatch requestLatch;
34+
35+
@BeforeEach
36+
void setUp() throws IOException {
37+
requestLatch = new CountDownLatch(1);
38+
server = HttpServer.create(new InetSocketAddress(0), 0);
39+
server.createContext("/sse", new DelayedResultHandler(requestLatch));
40+
server.start();
41+
}
42+
43+
@AfterEach
44+
void tearDown() {
45+
server.stop(0);
46+
}
47+
48+
@Test
49+
void drainsResultEmittedAfterAssemblyFinished() throws Exception {
50+
String sseUrl = "http://localhost:" + server.getAddress().getPort() + "/sse";
51+
String sslUrl = "https://example.com/assemblies/123";
52+
53+
Transloadit transloadit = Mockito.mock(Transloadit.class);
54+
AssemblyResponse initialResponse = Mockito.mock(AssemblyResponse.class);
55+
JSONObject initialJson = new JSONObject().put("ok", "ASSEMBLY_UPLOADING");
56+
when(initialResponse.getSslUrl()).thenReturn(sslUrl);
57+
when(initialResponse.json()).thenReturn(initialJson);
58+
59+
AssemblyResponse finishedResponse = Mockito.mock(AssemblyResponse.class);
60+
JSONObject finishedJson = new JSONObject().put("ok", "ASSEMBLY_COMPLETED");
61+
when(finishedResponse.json()).thenReturn(finishedJson);
62+
when(transloadit.getAssemblyByUrl(anyString())).thenReturn(finishedResponse);
63+
64+
CountDownLatch finishedLatch = new CountDownLatch(1);
65+
CountDownLatch resultLatch = new CountDownLatch(1);
66+
AtomicReference<String> resultStep = new AtomicReference<>();
67+
68+
AssemblyListener listener = new AssemblyListener() {
69+
@Override
70+
public void onAssemblyFinished(AssemblyResponse response) {
71+
finishedLatch.countDown();
72+
}
73+
74+
@Override
75+
public void onError(Exception error) {
76+
throw new AssertionError("Unexpected SSE error", error);
77+
}
78+
79+
@Override public void onMetadataExtracted() { }
80+
@Override public void onAssemblyUploadFinished() { }
81+
@Override public void onFileUploadFinished(JSONObject uploadInformation) { }
82+
@Override public void onFileUploadPaused(String name) { }
83+
@Override public void onFileUploadResumed(String name) { }
84+
@Override public void onFileUploadProgress(long uploadedBytes, long totalBytes) { }
85+
@Override public void onAssemblyProgress(JSONObject progressPerOriginalFile) { }
86+
87+
@Override
88+
public void onAssemblyResultFinished(org.json.JSONArray result) {
89+
resultStep.compareAndSet(null, result.optString(0));
90+
resultLatch.countDown();
91+
}
92+
};
93+
94+
ConnectStrategy connectStrategy = ConnectStrategy.http(URI.create(sseUrl));
95+
RetryDelayStrategy retryStrategy = RetryDelayStrategy.defaultStrategy();
96+
ErrorStrategy errorStrategy = ErrorStrategy.alwaysContinue();
97+
98+
EventsourceRunnable runnable = new EventsourceRunnable(
99+
transloadit,
100+
initialResponse,
101+
listener,
102+
connectStrategy,
103+
retryStrategy,
104+
errorStrategy,
105+
false
106+
);
107+
108+
Thread thread = new Thread(runnable, "sse-delayed-result-test");
109+
thread.start();
110+
111+
assertTrue(requestLatch.await(5, TimeUnit.SECONDS), "SSE server not contacted");
112+
assertTrue(finishedLatch.await(5, TimeUnit.SECONDS), "assembly_finished not received");
113+
assertTrue(resultLatch.await(15, TimeUnit.SECONDS), "Delayed result not received");
114+
assertEquals("resize", resultStep.get(), "Unexpected step name");
115+
116+
thread.join(TimeUnit.SECONDS.toMillis(5));
117+
}
118+
119+
private static final class DelayedResultHandler implements HttpHandler {
120+
private final CountDownLatch latch;
121+
122+
private DelayedResultHandler(CountDownLatch latch) {
123+
this.latch = latch;
124+
}
125+
126+
@Override
127+
public void handle(HttpExchange exchange) throws IOException {
128+
latch.countDown();
129+
exchange.getResponseHeaders().add("Content-Type", "text/event-stream");
130+
exchange.sendResponseHeaders(200, 0);
131+
try (OutputStream os = exchange.getResponseBody()) {
132+
write(os, "event: message\n");
133+
write(os, "data: assembly_finished\n\n");
134+
sleep(3000);
135+
write(os, "event: assembly_result_finished\n");
136+
write(os, "data: [\"resize\",{\"id\":\"abc\"}]\n\n");
137+
} finally {
138+
exchange.close();
139+
}
140+
}
141+
142+
private static void write(OutputStream os, String value) throws IOException {
143+
os.write(value.getBytes(StandardCharsets.UTF_8));
144+
os.flush();
145+
}
146+
147+
private static void sleep(long millis) {
148+
try {
149+
Thread.sleep(millis);
150+
} catch (InterruptedException ignored) {
151+
}
152+
}
153+
}
154+
}

src/test/java/com/transloadit/sdk/integration/AssemblySseIntegrationTest.java renamed to src/test/java/com/transloadit/sdk/integration/AssemblySseIntegrationTestIT.java

File renamed without changes.

0 commit comments

Comments
 (0)