Skip to content

Commit aa0553b

Browse files
committed
refactor(deploy): shuffle deploy job code for clarity
1 parent 7c92c1d commit aa0553b

File tree

1 file changed

+71
-64
lines changed

1 file changed

+71
-64
lines changed

src/main/java/com/conveyal/datatools/manager/jobs/DeployJob.java

+71-64
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ public class DeployJob extends MonitorableJob {
7373

7474
private static final Logger LOG = LoggerFactory.getLogger(DeployJob.class);
7575
private static final String bundlePrefix = "bundles";
76+
/**
77+
* S3 bucket to upload deployment to. If not null, uses {@link OtpServer#s3Bucket}. Otherwise, defaults to
78+
* {@link DataManager#feedBucket}
79+
* */
80+
private final String s3Bucket;
81+
private final int targetCount;
82+
private int tasksCompleted = 0;
83+
private int totalTasks;
7684

7785
private AmazonEC2 ec2;
7886
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
@@ -89,6 +97,7 @@ public class DeployJob extends MonitorableJob {
8997
/** This hides the status field on the parent class, providing additional fields. */
9098
public DeployStatus status;
9199

100+
private String statusMessage;
92101
private int serverCounter = 0;
93102
// private String imageId;
94103
private String dateString = DATE_FORMAT.format(new Date());
@@ -105,8 +114,11 @@ public DeployJob(Deployment deployment, String owner, OtpServer otpServer) {
105114
super(owner, "Deploying " + deployment.name, JobType.DEPLOY_TO_OTP);
106115
this.deployment = deployment;
107116
this.otpServer = otpServer;
117+
this.s3Bucket = otpServer.s3Bucket != null ? otpServer.s3Bucket : DataManager.feedBucket;
108118
// Use a special subclass of status here that has additional fields
109119
this.status = new DeployStatus();
120+
this.targetCount = otpServer.internalUrl != null ? otpServer.internalUrl.size() : 0;
121+
this.totalTasks = 1 + targetCount;
110122
status.message = "Initializing...";
111123
status.built = false;
112124
status.numServersCompleted = 0;
@@ -118,14 +130,9 @@ public DeployJob(Deployment deployment, String owner, OtpServer otpServer) {
118130
}
119131

120132
public void jobLogic () {
121-
int targetCount = otpServer.internalUrl != null ? otpServer.internalUrl.size() : 0;
122-
int totalTasks = 1 + targetCount;
123133
if (otpServer.s3Bucket != null) totalTasks++;
124134
// FIXME
125135
if (otpServer.targetGroupArn != null) totalTasks++;
126-
int tasksCompleted = 0;
127-
String statusMessage;
128-
129136
try {
130137
deploymentTempFile = File.createTempFile("deployment", ".zip");
131138
} catch (IOException e) {
@@ -155,49 +162,22 @@ public void jobLogic () {
155162
LOG.info("Deployment pctComplete = {}", status.percentComplete);
156163
status.built = true;
157164

158-
// Upload to S3, if applicable
159-
if(otpServer.s3Bucket != null) {
160-
status.message = "Uploading to S3";
161-
status.uploadingS3 = true;
162-
String key = getS3BundleKey();
163-
LOG.info("Uploading deployment {} to s3://{}/{}", deployment.name, otpServer.s3Bucket, key);
165+
// Upload to S3, if specifically required by the OTPServer or needed for servers in the target group to fetch.
166+
if (otpServer.s3Bucket != null || otpServer.targetGroupArn != null) {
164167
try {
165-
// PutObjectRequest putObjectRequest = new PutObjectRequest(otpServer.s3Bucket, key, deploymentTempFile).;
166-
TransferManager tx = TransferManagerBuilder.standard().withS3Client(FeedStore.s3Client).build();
167-
final Upload upload = tx.upload(otpServer.s3Bucket, key, deploymentTempFile);
168-
169-
upload.addProgressListener((ProgressListener) progressEvent -> {
170-
status.percentUploaded = upload.getProgress().getPercentTransferred();
171-
});
172-
173-
upload.waitForCompletion();
174-
175-
// Shutdown the Transfer Manager, but don't shut down the underlying S3 client.
176-
// The default behavior for shutdownNow shut's down the underlying s3 client
177-
// which will cause any following s3 operations to fail.
178-
tx.shutdownNow(false);
179-
180-
// copy to [name]-latest.zip
181-
String copyKey = getLatestS3BundleKey();
182-
CopyObjectRequest copyObjRequest = new CopyObjectRequest(
183-
otpServer.s3Bucket, key, otpServer.s3Bucket, copyKey);
184-
FeedStore.s3Client.copyObject(copyObjRequest);
185-
LOG.info("Copied to s3://{}/{}", otpServer.s3Bucket, copyKey);
186-
} catch (AmazonClientException|InterruptedException e) {
187-
statusMessage = String.format("Error uploading (or copying) deployment bundle to s3://%s/%s", otpServer.s3Bucket, key);
188-
LOG.error(statusMessage);
189-
e.printStackTrace();
168+
uploadBundleToS3();
169+
} catch (AmazonClientException | InterruptedException e) {
170+
statusMessage = String.format("Error uploading (or copying) deployment bundle to s3://%s", s3Bucket);
171+
LOG.error(statusMessage, e);
190172
status.fail(statusMessage);
191-
return;
192173
}
193-
LOG.info("Uploaded to s3://{}/{}", otpServer.s3Bucket, getS3BundleKey());
194-
status.update("Upload to S3 complete.", status.percentComplete + 10);
195-
status.uploadingS3 = false;
174+
196175
}
197176

177+
// Handle spinning up new EC2 servers for the load balancer's target group.
198178
if (otpServer.targetGroupArn != null) {
199179
if ("true".equals(DataManager.getConfigPropertyAsText("modules.deployment.ec2.enabled"))) {
200-
createServer();
180+
replaceEC2Servers();
201181
// If creating a new server, there is no need to deploy to an existing one.
202182
return;
203183
} else {
@@ -209,11 +189,46 @@ public void jobLogic () {
209189
}
210190

211191
// If there are no OTP targets (i.e. we're only deploying to S3), we're done.
212-
if(otpServer.internalUrl == null) {
213-
status.completed = true;
214-
return;
192+
if(otpServer.internalUrl != null) {
193+
// If we come to this point, there are internal URLs we need to deploy to (i.e., build graph over the wire).
194+
boolean sendOverWireSuccessful = buildGraphOverWire();
195+
if (!sendOverWireSuccessful) return;
196+
// Set baseUrl after success.
197+
status.baseUrl = otpServer.publicUrl;
215198
}
199+
status.completed = true;
200+
}
216201

202+
private void uploadBundleToS3() throws InterruptedException, AmazonClientException {
203+
status.message = "Uploading to S3";
204+
status.uploadingS3 = true;
205+
String key = getS3BundleKey();
206+
LOG.info("Uploading deployment {} to s3://{}/{}", deployment.name, s3Bucket, key);
207+
TransferManager tx = TransferManagerBuilder.standard().withS3Client(FeedStore.s3Client).build();
208+
final Upload upload = tx.upload(s3Bucket, key, deploymentTempFile);
209+
210+
upload.addProgressListener(
211+
(ProgressListener) progressEvent -> status.percentUploaded = upload.getProgress().getPercentTransferred()
212+
);
213+
214+
upload.waitForCompletion();
215+
216+
// Shutdown the Transfer Manager, but don't shut down the underlying S3 client.
217+
// The default behavior for shutdownNow shut's down the underlying s3 client
218+
// which will cause any following s3 operations to fail.
219+
tx.shutdownNow(false);
220+
221+
// copy to [name]-latest.zip
222+
String copyKey = getLatestS3BundleKey();
223+
CopyObjectRequest copyObjRequest = new CopyObjectRequest(s3Bucket, key, s3Bucket, copyKey);
224+
FeedStore.s3Client.copyObject(copyObjRequest);
225+
LOG.info("Copied to s3://{}/{}", s3Bucket, copyKey);
226+
LOG.info("Uploaded to s3://{}/{}", s3Bucket, getS3BundleKey());
227+
status.update("Upload to S3 complete.", status.percentComplete + 10);
228+
status.uploadingS3 = false;
229+
}
230+
231+
private boolean buildGraphOverWire() {
217232
// figure out what router we're using
218233
String router = deployment.routerId != null ? deployment.routerId : "default";
219234

@@ -267,7 +282,7 @@ public void jobLogic () {
267282
LOG.error(statusMessage);
268283
e.printStackTrace();
269284
status.fail(statusMessage);
270-
return;
285+
return false;
271286
}
272287

273288
// retrieveById the input file
@@ -277,7 +292,7 @@ public void jobLogic () {
277292
} catch (FileNotFoundException e) {
278293
LOG.error("Internal error: could not read dumped deployment!");
279294
status.fail("Internal error: could not read dumped deployment!");
280-
return;
295+
return false;
281296
}
282297

283298
try {
@@ -286,7 +301,7 @@ public void jobLogic () {
286301
statusMessage = String.format("Unable to open connection to OTP server %s", url);
287302
LOG.error(statusMessage);
288303
status.fail(statusMessage);
289-
return;
304+
return false;
290305
}
291306

292307
// copy
@@ -297,7 +312,7 @@ public void jobLogic () {
297312
LOG.error(statusMessage);
298313
e.printStackTrace();
299314
status.fail(statusMessage);
300-
return;
315+
return false;
301316
}
302317

303318
try {
@@ -307,7 +322,7 @@ public void jobLogic () {
307322
LOG.error(message);
308323
e.printStackTrace();
309324
status.fail(message);
310-
return;
325+
return false;
311326
}
312327

313328
try {
@@ -326,8 +341,8 @@ public void jobLogic () {
326341
if (code != HttpURLConnection.HTTP_CREATED) {
327342
// Get input/error stream from connection response.
328343
InputStream stream = code < HttpURLConnection.HTTP_BAD_REQUEST
329-
? conn.getInputStream()
330-
: conn.getErrorStream();
344+
? conn.getInputStream()
345+
: conn.getErrorStream();
331346
String response;
332347
try (Scanner scanner = new Scanner(stream)) {
333348
scanner.useDelimiter("\\Z");
@@ -338,7 +353,7 @@ public void jobLogic () {
338353
status.fail(statusMessage);
339354
// Skip deploying to any other servers.
340355
// There is no reason to take out the rest of the servers, it's going to have the same result.
341-
return;
356+
return false;
342357
}
343358
} catch (IOException e) {
344359
statusMessage = String.format("Could not finish request to server %s", url);
@@ -350,9 +365,7 @@ public void jobLogic () {
350365
tasksCompleted++;
351366
status.percentComplete = 100.0 * (double) tasksCompleted / totalTasks;
352367
}
353-
354-
status.completed = true;
355-
status.baseUrl = otpServer.publicUrl;
368+
return true;
356369
}
357370

358371
private String getS3BundleKey() {
@@ -388,7 +401,7 @@ public void jobFinished () {
388401
NotifyUsersForSubscriptionJob.createNotification("deployment-updated", deployment.id, message);
389402
}
390403

391-
public void createServer () {
404+
public void replaceEC2Servers() {
392405
try {
393406
// First start graph-building instance and wait for graph to successfully build.
394407
List<Instance> instances = startEC2Instances(1);
@@ -460,7 +473,7 @@ private List<Instance> startEC2Instances(int count) {
460473
// 2. Time to live until shutdown/termination (for test servers)
461474
// 3. Hosting / nginx
462475
// FIXME: Allow for r5 servers to be created.
463-
String userData = constructUserData(otpServer.s3Bucket, deployment.r5);
476+
String userData = constructUserData(deployment.r5);
464477
// The subnet ID should only change if starting up a server in some other AWS account. This is not
465478
// likely to be a requirement.
466479
// Define network interface so that a public IP can be associated with server.
@@ -538,7 +551,7 @@ private List<String> getIds (List<Instance> instances) {
538551
return instances.stream().map(Instance::getInstanceId).collect(Collectors.toList());
539552
}
540553

541-
private String constructUserData(String s3Bucket, boolean r5) {
554+
private String constructUserData(boolean r5) {
542555
// Prefix/name of JAR file (WITHOUT .jar) FIXME: make this configurable.
543556
String jarName = r5 ? deployment.r5Version : deployment.otpVersion;
544557
if (jarName == null) {
@@ -563,12 +576,6 @@ private String constructUserData(String s3Bucket, boolean r5) {
563576
lines.add(String.format("LOGFILE=/var/log/%s.log", tripPlanner));
564577
// Log user data setup to /var/log/user-data.log
565578
lines.add("exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1");
566-
// Install the necessary files to run the trip planner. FIXME Remove. This should be captured by the AMI.
567-
// lines.add("apt update -y");
568-
// lines.add("apt install -y openjdk-8-jre");
569-
// lines.add("apt install -y openjfx");
570-
// lines.add("apt install -y awscli");
571-
// lines.add("apt install -y unzip");
572579
// Create the directory for the graph inputs.
573580
lines.add(String.format("mkdir -p %s", routerDir));
574581
lines.add(String.format("chown ubuntu %s", routerDir));

0 commit comments

Comments
 (0)