Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,19 @@
max-height: 300px;
width: 450px;
overflow-y: auto;
}

.logBox {
display: flex;
justify-content: space-between;
flex-direction: row;
text-align: start;
margin-top: 10px;
padding: 10px;
border-radius: 5px;
max-height: 300px;
overflow-y: auto;
font-size: 14px;
align-items: flex-start;
border: 1px solid #ddd;
}
114 changes: 38 additions & 76 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { useEffect, useState } from "react";
import "./App.css";
import { queryFirebase, getLocationDict, getDocById, getFirebaseRecipe } from "./firebase";
import { queryFirebase, getLocationDict, getDocById, getFirebaseRecipe, getJobStatus } from "./firebase";
import {
getSubmitPackingUrl,
packingStatusUrl,
getLogsUrl,
JobStatus,
} from "./constants/awsBatch";
import {
FIRESTORE_COLLECTIONS
} from "./constants/firebaseConstants";
import { SIMULARIUM_EMBED_URL } from "./constants/urls";
import {
AWSBatchJobsResponse,
CloudWatchLogsResponse,
FirebaseDict,
} from "./types";

Expand All @@ -24,10 +20,7 @@ function App() {
const [selectedConfig, setSelectedConfig] = useState("");
const [jobId, setJobId] = useState("");
const [jobStatus, setJobStatus] = useState("");
const [logStreamName, setLogStreamName] = useState(
""
);
const [jobLogs, setJobLogs] = useState<string[]>([]);
const [jobLogs, setJobLogs] = useState<string>("");
const [resultUrl, setResultUrl] = useState<string>("");
const [recipeStr, setRecipeStr] = useState<string>("");
const [configStr, setConfigStr] = useState<string>("");
Expand All @@ -43,30 +36,24 @@ function App() {
return new Promise((resolve) => setTimeout(resolve, ms));
};

const submitRecipe = async (useECS: boolean = false) => {
const submitRecipe = async () => {
setResultUrl("");
setRunTime(0);
const firebaseRecipe = "firebase:recipes/" + selectedRecipe
const firebaseConfig = "firebase:configs/" + selectedConfig;
const url = getSubmitPackingUrl(firebaseRecipe, firebaseConfig, useECS);
const request: RequestInfo = new Request(url, {
method: useECS ? "GET" : "POST",
});
const url = getSubmitPackingUrl(firebaseRecipe, firebaseConfig);
const request: RequestInfo = new Request(url, { method: "POST" });
start = Date.now();
const response = await fetch(request);
setJobStatus(JobStatus.SUBMITTED);
const data = await response.json();
if (useECS) {
if (response.ok) {
const range = (Date.now() - start) / 1000;
setRunTime(range);
setJobId(data.jobId);
setJobStatus(JobStatus.SUCCEEDED);
return data.jobId;
} else {
setJobStatus(JobStatus.FAILED);
}
} else {
if (response.ok) {
setJobId(data.jobId);
setJobStatus(JobStatus.STARTING);
return data.jobId;
} else {
setJobStatus(JobStatus.FAILED);
setJobLogs(JSON.stringify(data));
}
};

Expand Down Expand Up @@ -99,58 +86,40 @@ function App() {

const checkStatus = async (jobIdFromSubmit: string) => {
const id = jobIdFromSubmit || jobId;
const url = packingStatusUrl(id);
const request: RequestInfo = new Request(
url,
{
method: "GET",
}
);
let localJobStatus = "";
while (localJobStatus !== JobStatus.SUCCEEDED && localJobStatus !== JobStatus.FAILED) {
const response = await fetch(request);
const data: AWSBatchJobsResponse = await response.json();
if (localJobStatus !== data.jobs[0].status) {
localJobStatus = data.jobs[0].status;
setJobStatus(data.jobs[0].status);
}
setLogStreamName(data.jobs[0].container.logStreamName);
let localJobStatus = await getJobStatus(id);
while (localJobStatus !== JobStatus.DONE && localJobStatus !== JobStatus.FAILED) {
await sleep(500);
const newJobStatus = await getJobStatus(id);
if (localJobStatus !== newJobStatus) {
localJobStatus = newJobStatus;
setJobStatus(newJobStatus);
}
}
const range = (Date.now() - start) / 1000;
setRunTime(range);
if (localJobStatus == JobStatus.DONE) {
fetchResultUrl(id);
} else if (localJobStatus == JobStatus.FAILED) {
getLogs(id);
}
};

const fetchResultUrl = async () => {
const url = await queryFirebase(jobId);
const fetchResultUrl = async (jobIdFromSubmit?: string) => {
const id = jobIdFromSubmit || jobId;
const url = await queryFirebase(id);
setResultUrl(SIMULARIUM_EMBED_URL + url);
};

const getLogs = async () => {
const url = getLogsUrl(logStreamName);
const request: RequestInfo = new Request(
url,
{
method: "GET",
}
);
const response = await fetch(request);
const data: CloudWatchLogsResponse = await response.json();
const logs = data.events.map((event: { message: string }) => event.message);
setJobLogs(logs);
};

const runPacking = async () => {
submitRecipe().then((jobIdFromSubmit) => checkStatus(jobIdFromSubmit));
setViewConfig(false);
setViewRecipe(false);
const getLogs = async (jobIdFromSubmit?: string) => {
const id = jobIdFromSubmit || jobId;
const logStr: string = await getDocById(FIRESTORE_COLLECTIONS.JOB_STATUS, id);
setJobLogs(logStr);
};

const runPackingECS = async () => {
submitRecipe(true);
setJobStatus(JobStatus.SUBMITTED);
setViewConfig(false);
setViewRecipe(false);
submitRecipe().then((jobIdFromSubmit) => checkStatus(jobIdFromSubmit));
};

const selectRecipe = async (recipe: string) => {
Expand Down Expand Up @@ -188,8 +157,8 @@ function App() {
}
}

const jobSucceeded = jobStatus == JobStatus.SUCCEEDED;
const showLogButton = jobSucceeded || jobStatus == JobStatus.FAILED;
const jobSucceeded = jobStatus == JobStatus.DONE;
const showLogButton = jobStatus == JobStatus.FAILED;
const showResults = resultUrl && viewResults;

return (
Expand Down Expand Up @@ -222,11 +191,8 @@ function App() {
</option>
))}
</select>
<button onClick={runPacking} disabled={!selectedRecipe}>
Pack on Batch
</button>
<button onClick={runPackingECS} disabled={!selectedRecipe}>
Pack on ECS
Pack
</button>
</div>
<div className="box">
Expand Down Expand Up @@ -254,7 +220,7 @@ function App() {
<h3>Job Status: {jobStatus}</h3>
{jobSucceeded && (
<div>
<h4>Time to Run: {runTime} sec</h4>
{runTime > 0 && (<h4>Time to Run: {runTime} sec</h4>)}
<button onClick={toggleResults}>Results</button>
</div>
)}
Expand All @@ -276,12 +242,8 @@ function App() {
<div>
<button className="collapsible" onClick={toggleLogs}>Logs</button>
{viewLogs && jobLogs.length > 0 && (
<div className="logs-container">
{jobLogs.map((log, index) => (
<div key={index} className="log-entry">
<span>{log}</span>
</div>
))}
<div className="logBox">
<pre>{jobLogs}</pre>
</div>
)}
</div>
Expand Down
17 changes: 3 additions & 14 deletions src/constants/awsBatch.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,22 @@
//api endpoints
const BASE_URL = "https://ng44ddk8v1.execute-api.us-west-2.amazonaws.com/testing";
const SUBMIT_PACKING_BASE = `${BASE_URL}/submit-packing`;
const SUBMIT_PACKING_ECS = "https://bda21vau5c.execute-api.us-west-2.amazonaws.com/staging/pack";
const PACKING_STATUS_BASE = `${BASE_URL}/packing-status`;
const GET_LOGS_BASE = `${BASE_URL}/logs`;
const SUBMIT_PACKING_ECS = "https://bda21vau5c.execute-api.us-west-2.amazonaws.com/production/start-packing";

export const getSubmitPackingUrl = (
recipe: string,
config?: string,
useECS: boolean = false
) => {
const baseURL = useECS ? SUBMIT_PACKING_ECS : SUBMIT_PACKING_BASE;
let url = `${baseURL}?recipe=${recipe}`;
let url = `${SUBMIT_PACKING_ECS}?recipe=${recipe}`;
if (config) {
url += `&config=${config}`;
}
return url;
}

export const packingStatusUrl = (jobId: string) => `${PACKING_STATUS_BASE}?jobId=${jobId}`;
export const getLogsUrl = (logStreamName: string) => `${GET_LOGS_BASE}?logStreamName=${logStreamName}`;

//job status
export enum JobStatus {
SUBMITTED = "SUBMITTED",
PENDING = "PENDING",
RUNNABLE = "RUNNABLE",
STARTING = "STARTING",
RUNNING = "RUNNING",
SUCCEEDED = "SUCCEEDED",
DONE = "DONE",
FAILED = "FAILED",
}
1 change: 1 addition & 0 deletions src/constants/firebaseConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const FIRESTORE_COLLECTIONS = {
GRADIENTS: "gradients",
COMPOSITION: "composition",
EXAMPLE_RECIPES: "example_recipes",
JOB_STATUS: "job_status",
};

//firestore field names
Expand Down
16 changes: 15 additions & 1 deletion src/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ const queryFirebase = async (jobId: string) => {
return resultUrl;
};

const getJobStatus = async (jobId: string) => {
const q = query(
collection(db, FIRESTORE_COLLECTIONS.JOB_STATUS),
where(documentId(), "==", jobId)
);
const querySnapshot = await getDocs(q);
let status = "";
querySnapshot.forEach((doc) => {
// we'll only ever expect one doc to show up here
status = doc.data().status;
});
return status;
}

const getAllDocsFromCollection = async (collectionName: string) => {
const q = query(collection(db, collectionName));
const querySnapshot = await getDocs(q);
Expand Down Expand Up @@ -237,4 +251,4 @@ const getFirebaseRecipe = async (name: string): Promise<string> => {
return unpackedRecipe;
}

export { db, queryFirebase, getLocationDict, getDocById, getFirebaseRecipe };
export { db, queryFirebase, getLocationDict, getDocById, getFirebaseRecipe, getJobStatus };