Skip to content

Commit dde947e

Browse files
committed
Add a scheduled task to ping home (#560)
* Add a scheduled task to ping home * Removed commented logging code * Add docstrings to ping scheduled task * Move IP address API URI to a constant
1 parent 04368d6 commit dde947e

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

app/server/appsmith-server/src/main/java/com/appsmith/server/ServerApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.scheduling.annotation.EnableScheduling;
56

67
@SpringBootApplication
8+
@EnableScheduling
79
public class ServerApplication {
810

911
public static void main(String[] args) {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.appsmith.server.solutions;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
5+
import org.springframework.http.MediaType;
6+
import org.springframework.scheduling.annotation.Scheduled;
7+
import org.springframework.stereotype.Component;
8+
import org.springframework.web.reactive.function.BodyInserters;
9+
import org.springframework.web.reactive.function.client.WebClient;
10+
import reactor.core.publisher.Mono;
11+
import reactor.core.scheduler.Schedulers;
12+
13+
import java.net.URI;
14+
import java.util.Map;
15+
16+
/**
17+
* This class represents a scheduled task that pings a data point indicating that this server installation is live.
18+
*/
19+
@Component
20+
@ConditionalOnProperty(prefix = "is", name = "self-hosted")
21+
@Slf4j
22+
public class PingScheduledTask {
23+
24+
public static final URI GET_IP_URI = URI.create("https://api6.ipify.org");
25+
26+
/**
27+
* Gets the external IP address of this server and pings a data point to indicate that this server instance is live.
28+
*/
29+
// Number of milliseconds between the start of each scheduled calls to this method.
30+
@Scheduled(fixedRate = 6 * 60 * 60 * 1000 /* six hours */)
31+
public void pingSchedule() {
32+
getInstallationId()
33+
.flatMap(this::doPing)
34+
.doOnError(error -> log.debug("Error pinging home", error))
35+
.subscribeOn(Schedulers.single())
36+
.subscribe();
37+
}
38+
39+
/**
40+
* This method hits an API endpoint that returns the external IP address of this server instance.
41+
* @return A publisher that yields the IP address.
42+
*/
43+
private Mono<String> getInstallationId() {
44+
return WebClient
45+
.create()
46+
.get()
47+
.uri(GET_IP_URI)
48+
.retrieve()
49+
.bodyToMono(String.class);
50+
}
51+
52+
/**
53+
* Given a unique ID (called a `userId` here), this method hits the Segment API to save a data point on this server
54+
* instance being live.
55+
* @param userId A unique identifier for this server instance (usually, the external IP address of the server).
56+
* @return A publisher that yields the string response of recording the data point.
57+
*/
58+
private Mono<String> doPing(String userId) {
59+
// Note: Hard-coding Segment auth header and the event name intentionally. These are not intended to be
60+
// environment specific values, instead, they are common values for all self-hosted environments. As such, they
61+
// are not intended to be configurable.
62+
return WebClient
63+
.create("https://api.segment.io")
64+
.post()
65+
.uri("/v1/track")
66+
.header("Authorization", "Basic QjJaM3hXRThXdDRwYnZOWDRORnJPNWZ3VXdnYWtFbk06")
67+
.contentType(MediaType.APPLICATION_JSON)
68+
.body(BodyInserters.fromValue(Map.of(
69+
"userId", userId,
70+
"event", "Instance Active"
71+
)))
72+
.retrieve()
73+
.bodyToMono(String.class);
74+
}
75+
76+
}

app/server/appsmith-server/src/main/resources/application.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ marketplace.base-url = ${APPSMITH_MARKETPLACE_URL:}
5757
marketplace.username=${APPSMITH_MARKETPLACE_USERNAME:}
5858
marketplace.password=${APPSMITH_MARKETPLACE_PASSWORD:}
5959

60+
# Is this a self-hosted instance?
61+
is.self-hosted = ${APPSMITH_IS_SELF_HOSTED:true}
62+
6063
# MANDATORY!! No default properties are being provided for encryption password and salt for security.
6164
# The server would not come up without these values provided through the environment variables.
6265
encrypt.password=${APPSMITH_ENCRYPTION_PASSWORD:}

0 commit comments

Comments
 (0)