Optimize: Made Workflow workers self-destruct at times
This commit is contained in:
@@ -40,3 +40,6 @@ SHUFFLE_PASS_WORKER_PROXY=TRUE
|
|||||||
SHUFFLE_BASE_IMAGE_REGISTRY=ghcr.io
|
SHUFFLE_BASE_IMAGE_REGISTRY=ghcr.io
|
||||||
SHUFFLE_BASE_IMAGE_NAME=frikky
|
SHUFFLE_BASE_IMAGE_NAME=frikky
|
||||||
SHUFFLE_BASE_IMAGE_TAG_SUFFIX="-0.8.3"
|
SHUFFLE_BASE_IMAGE_TAG_SUFFIX="-0.8.3"
|
||||||
|
|
||||||
|
# Used for auto-cleanup of containers. REALLY important at scale.
|
||||||
|
SHUFFLE_CONTAINER_AUTO_CLEANUP=false
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class AppBase:
|
|||||||
# apikey is for the user / org
|
# apikey is for the user / org
|
||||||
# authorization is for the specific workflow
|
# authorization is for the specific workflow
|
||||||
self.url = os.getenv("CALLBACK_URL", "https://shuffler.io")
|
self.url = os.getenv("CALLBACK_URL", "https://shuffler.io")
|
||||||
self.base_url = os.getenv("BASE_URL", "https://shuffler.io")
|
self.base_url = os.getenv("BASE_URL", "")
|
||||||
self.action = os.getenv("ACTION", "")
|
self.action = os.getenv("ACTION", "")
|
||||||
self.authorization = os.getenv("AUTHORIZATION", "")
|
self.authorization = os.getenv("AUTHORIZATION", "")
|
||||||
self.current_execution_id = os.getenv("EXECUTIONID", "")
|
self.current_execution_id = os.getenv("EXECUTIONID", "")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
NAME=shuffle-app_sdk
|
NAME=shuffle-app_sdk
|
||||||
VERSION=0.8.52
|
VERSION=0.8.53
|
||||||
|
|
||||||
docker rmi docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION --force
|
docker rmi docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION --force
|
||||||
docker build . -t frikky/shuffle:app_sdk -t frikky/$NAME:$VERSION -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t ghcr.io/frikky/$NAME:$VERSION
|
docker build . -t frikky/shuffle:app_sdk -t frikky/$NAME:$VERSION -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t ghcr.io/frikky/$NAME:$VERSION
|
||||||
|
|||||||
@@ -397,12 +397,11 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
|
|||||||
verifyAddin,
|
verifyAddin,
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
//log.Printf("FUNCTION: %s", data)
|
||||||
if strings.Contains(functionname, "search") {
|
//if strings.Contains(functionname, "search") {
|
||||||
log.Println(data)
|
// log.Println(data)
|
||||||
log.Printf("Queries: %s", queryString)
|
// log.Printf("Queries: %s", queryString)
|
||||||
}
|
//}
|
||||||
*/
|
|
||||||
|
|
||||||
//log.Printf(data)
|
//log.Printf(data)
|
||||||
return functionname, data
|
return functionname, data
|
||||||
|
|||||||
@@ -917,12 +917,13 @@ func validateNewWorkerExecution(body []byte) error {
|
|||||||
return errors.New("Bad authorization when validating execution")
|
return errors.New("Bad authorization when validating execution")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used to validate if it's actually the right marshal
|
||||||
if len(baseExecution.Workflow.Actions) != len(execution.Workflow.Actions) {
|
if len(baseExecution.Workflow.Actions) != len(execution.Workflow.Actions) {
|
||||||
return errors.New(fmt.Sprintf("Bad length of actions: %d", len(execution.Workflow.Actions)))
|
return errors.New(fmt.Sprintf("Bad length of actions (probably normal app): %d", len(execution.Workflow.Actions)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(baseExecution.Workflow.Triggers) != len(execution.Workflow.Triggers) {
|
if len(baseExecution.Workflow.Triggers) != len(execution.Workflow.Triggers) {
|
||||||
return errors.New(fmt.Sprintf("Bad length of trigger: %d", len(execution.Workflow.Triggers)))
|
return errors.New(fmt.Sprintf("Bad length of trigger: %d (probably normal app)", len(execution.Workflow.Triggers)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Add extra here
|
// FIXME: Add extra here
|
||||||
@@ -933,8 +934,11 @@ func validateNewWorkerExecution(body []byte) error {
|
|||||||
|
|
||||||
//log.Printf("\n\nSHOULD SET BACKEND DATA FOR EXEC \n\n")
|
//log.Printf("\n\nSHOULD SET BACKEND DATA FOR EXEC \n\n")
|
||||||
err = setWorkflowExecution(ctx, execution, true)
|
err = setWorkflowExecution(ctx, execution, true)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
log.Printf("Successfully set the execution to wait.")
|
log.Printf("[INFO] Set workflowexecution based on new worker (>0.8.53) for execution %s", baseExecution.ExecutionId)
|
||||||
|
//log.Printf("[INFO] Successfully set the execution to wait.")
|
||||||
|
} else {
|
||||||
|
log.Printf("[WARNING] Failed to set the execution to wait.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -957,12 +961,11 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
|||||||
//log.Printf("Actionresult unmarshal: %s", string(body))
|
//log.Printf("Actionresult unmarshal: %s", string(body))
|
||||||
err = validateNewWorkerExecution(body)
|
err = validateNewWorkerExecution(body)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Printf("[INFO] Set workflowexecution based on new worker")
|
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "Success"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "Success"}`)))
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[WARNING] Failed to handle new execution variant: %s", err)
|
//log.Printf("[WARNING] Failed to handle new execution variant: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var actionResult ActionResult
|
var actionResult ActionResult
|
||||||
|
|||||||
+4
-3
@@ -1,8 +1,8 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
frontend:
|
frontend:
|
||||||
#build: ./frontend
|
build: ./frontend
|
||||||
image: ghcr.io/frikky/shuffle-frontend:0.8.51
|
image: ghcr.io/frikky/shuffle-frontend:0.8.52
|
||||||
container_name: shuffle-frontend
|
container_name: shuffle-frontend
|
||||||
hostname: shuffle-frontend
|
hostname: shuffle-frontend
|
||||||
ports:
|
ports:
|
||||||
@@ -17,7 +17,7 @@ services:
|
|||||||
- backend
|
- backend
|
||||||
backend:
|
backend:
|
||||||
#build: ./backend
|
#build: ./backend
|
||||||
image: ghcr.io/frikky/shuffle-backend:0.8.51
|
image: ghcr.io/frikky/shuffle-backend:0.8.52
|
||||||
container_name: shuffle-backend
|
container_name: shuffle-backend
|
||||||
hostname: ${BACKEND_HOSTNAME}
|
hostname: ${BACKEND_HOSTNAME}
|
||||||
# Here for debugging:
|
# Here for debugging:
|
||||||
@@ -66,6 +66,7 @@ services:
|
|||||||
- SHUFFLE_BASE_IMAGE_NAME=${SHUFFLE_BASE_IMAGE_NAME}
|
- SHUFFLE_BASE_IMAGE_NAME=${SHUFFLE_BASE_IMAGE_NAME}
|
||||||
- SHUFFLE_BASE_IMAGE_REGISTRY=${SHUFFLE_BASE_IMAGE_REGISTRY}
|
- SHUFFLE_BASE_IMAGE_REGISTRY=${SHUFFLE_BASE_IMAGE_REGISTRY}
|
||||||
- SHUFFLE_BASE_IMAGE_TAG_SUFFIX=${SHUFFLE_BASE_IMAGE_TAG_SUFFIX}
|
- SHUFFLE_BASE_IMAGE_TAG_SUFFIX=${SHUFFLE_BASE_IMAGE_TAG_SUFFIX}
|
||||||
|
- CLEANUP=${SHUFFLE_CONTAINER_AUTO_CLEANUP}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
database:
|
database:
|
||||||
#build: ./backend/database
|
#build: ./backend/database
|
||||||
|
|||||||
@@ -4276,11 +4276,18 @@ const AngularWorkflow = (props) => {
|
|||||||
color="primary"
|
color="primary"
|
||||||
defaultValue={data.value}
|
defaultValue={data.value}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
|
helperText={data.value !== undefined && data.value !== null && data.value.includes(".#") ?
|
||||||
|
<span style={{color:"white", marginBottom: 5, marginleft: 5,}}>
|
||||||
|
Use "Shuffle Tools" app with "Filter List" action to handle loops
|
||||||
|
</span>
|
||||||
|
: null
|
||||||
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log("CHANGE FIELD")
|
console.log("CHANGE FIELD")
|
||||||
}}
|
}}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
changeActionVariable(data.action_field, e.target.value)
|
changeActionVariable(data.action_field, e.target.value)
|
||||||
|
setUpdate(Math.random())
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -4473,8 +4480,10 @@ const AngularWorkflow = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<DialogTitle><div style={{color:"white"}}>Condition</div></DialogTitle>
|
<DialogTitle><span style={{color:"white"}}>Condition</span>
|
||||||
<DialogContent style={{display: "flex"}}>
|
</DialogTitle>
|
||||||
|
<DialogContent style={{}}>
|
||||||
|
<div style={{display: "flex"}}>
|
||||||
<Tooltip color="primary" title={conditionValue.configuration ? "Negated" : "Default"} placement="top">
|
<Tooltip color="primary" title={conditionValue.configuration ? "Negated" : "Default"} placement="top">
|
||||||
<Button color="primary" variant={conditionValue.configuration ? "contained" : "outlined"} style={{margin: "auto", height: 50, marginBottom: "auto", marginTop: "auto", marginRight: 5}} onClick={(e) => {
|
<Button color="primary" variant={conditionValue.configuration ? "contained" : "outlined"} style={{margin: "auto", height: 50, marginBottom: "auto", marginTop: "auto", marginRight: 5}} onClick={(e) => {
|
||||||
conditionValue.configuration = !conditionValue.configuration
|
conditionValue.configuration = !conditionValue.configuration
|
||||||
@@ -4556,38 +4565,43 @@ const AngularWorkflow = (props) => {
|
|||||||
<div style={{flex: "2"}}>
|
<div style={{flex: "2"}}>
|
||||||
<AppConditionHandler tmpdata={destinationValue} setData={setDestinationValue} type={"destination"} />
|
<AppConditionHandler tmpdata={destinationValue} setData={setDestinationValue} type={"destination"} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<span style={{marginTop: 15}}>
|
||||||
|
Conditions can't be used for loops [ .# ]. <a target="_blank" href="https://shuffler.io/docs/conditions" style={{textDecoration: "none", color: "#f85a3e"}}>Learn more</a>
|
||||||
|
</span>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
style={{borderRadius: "0px"}}
|
style={{borderRadius: "0px"}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedEdge({})
|
setSelectedEdge({})
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
condition: conditionValue,
|
condition: conditionValue,
|
||||||
source: sourceValue,
|
source: sourceValue,
|
||||||
destination: destinationValue,
|
destination: destinationValue,
|
||||||
}
|
|
||||||
|
|
||||||
setConditionsModalOpen(false)
|
|
||||||
if (selectedEdge.conditions === undefined) {
|
|
||||||
selectedEdge.conditions = [data]
|
|
||||||
} else {
|
|
||||||
const curedgeindex = selectedEdge.conditions.findIndex(data => data.source.id === sourceValue.id)
|
|
||||||
if (curedgeindex < 0) {
|
|
||||||
selectedEdge.conditions.push(data)
|
|
||||||
} else {
|
|
||||||
selectedEdge.conditions[curedgeindex] = data
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
setSelectedEdge(selectedEdge)
|
setConditionsModalOpen(false)
|
||||||
workflow.branches[selectedEdgeIndex] = selectedEdge
|
if (selectedEdge.conditions === undefined) {
|
||||||
setWorkflow(workflow)
|
selectedEdge.conditions = [data]
|
||||||
}} color="primary">
|
} else {
|
||||||
Submit
|
const curedgeindex = selectedEdge.conditions.findIndex(data => data.source.id === sourceValue.id)
|
||||||
</Button>
|
if (curedgeindex < 0) {
|
||||||
</DialogActions>
|
selectedEdge.conditions.push(data)
|
||||||
|
} else {
|
||||||
|
selectedEdge.conditions[curedgeindex] = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectedEdge(selectedEdge)
|
||||||
|
workflow.branches[selectedEdgeIndex] = selectedEdge
|
||||||
|
setWorkflow(workflow)
|
||||||
|
}} color="primary">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
@@ -6422,15 +6436,20 @@ const AngularWorkflow = (props) => {
|
|||||||
:
|
:
|
||||||
<div style={{padding: 25, maxWidth: 365, overflowX: "hidden",}}>
|
<div style={{padding: 25, maxWidth: 365, overflowX: "hidden",}}>
|
||||||
<Breadcrumbs aria-label="breadcrumb" separator="›" style={{color: "white", fontSize: 16}}>
|
<Breadcrumbs aria-label="breadcrumb" separator="›" style={{color: "white", fontSize: 16}}>
|
||||||
<h2 style={{color: "rgba(255,255,255,0.5)", cursor: "pointer"}} onClick={() => {
|
<span style={{color: "rgba(255,255,255,0.5)", display: "flex"}} onClick={() => {
|
||||||
setExecutionRunning(false)
|
setExecutionRunning(false)
|
||||||
stop()
|
stop()
|
||||||
getWorkflowExecution(props.match.params.key)
|
getWorkflowExecution(props.match.params.key)
|
||||||
setExecutionModalView(0)
|
setExecutionModalView(0)
|
||||||
}}>
|
}}>
|
||||||
<ArrowBackIcon style={{marginRight: 7, }} />
|
<IconButton style={{paddingLeft: 0, marginTop: "auto", marginBottom: "auto", }} onClick={() => {}}>
|
||||||
See other Executions
|
<ArrowBackIcon style={{color: "rgba(255,255,255,0.5)",}} />
|
||||||
</h2>
|
</IconButton>
|
||||||
|
<h2 style={{color: "rgba(255,255,255,0.5)", cursor: "pointer"}} onClick={() => {
|
||||||
|
}}>
|
||||||
|
See other Executions
|
||||||
|
</h2>
|
||||||
|
</span>
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
<Divider style={{backgroundColor: "white", marginTop: 10, marginBottom: 10,}}/>
|
<Divider style={{backgroundColor: "white", marginTop: 10, marginBottom: 10,}}/>
|
||||||
<h2>Executing Workflow</h2>
|
<h2>Executing Workflow</h2>
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ const Apps = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var description = data.description
|
var description = data.description
|
||||||
const maxDescLen = 60
|
const maxDescLen = 58
|
||||||
if (description.length > maxDescLen) {
|
if (description.length > maxDescLen) {
|
||||||
description = data.description.slice(0, maxDescLen)+"..."
|
description = data.description.slice(0, maxDescLen)+"..."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
NAME=shuffle-orborus
|
NAME=shuffle-orborus
|
||||||
VERSION=0.8.52
|
VERSION=0.8.53
|
||||||
|
|
||||||
echo "Running docker build with $NAME:$VERSION"
|
echo "Running docker build with $NAME:$VERSION"
|
||||||
#docker rmi frikky/shuffle:$NAME --force
|
#docker rmi frikky/shuffle:$NAME --force
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ var baseUrl = os.Getenv("BASE_URL")
|
|||||||
var environment = os.Getenv("ENVIRONMENT_NAME")
|
var environment = os.Getenv("ENVIRONMENT_NAME")
|
||||||
var dockerApiVersion = os.Getenv("DOCKER_API_VERSION")
|
var dockerApiVersion = os.Getenv("DOCKER_API_VERSION")
|
||||||
var runningMode = strings.ToLower(os.Getenv("RUNNING_MODE"))
|
var runningMode = strings.ToLower(os.Getenv("RUNNING_MODE"))
|
||||||
|
var cleanupEnv = strings.ToLower(os.Getenv("CLEANUP"))
|
||||||
|
var workerIds = []string{}
|
||||||
|
|
||||||
type ExecutionRequestWrapper struct {
|
type ExecutionRequestWrapper struct {
|
||||||
Data []ExecutionRequest `json:"data"`
|
Data []ExecutionRequest `json:"data"`
|
||||||
@@ -144,6 +146,10 @@ func deployWorker(image string, identifier string, env []string) {
|
|||||||
//log.Printf("[INFO] Empty self container id, continue without NetworkMode")
|
//log.Printf("[INFO] Empty self container id, continue without NetworkMode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cleanupEnv == "true" {
|
||||||
|
hostConfig.AutoRemove = true
|
||||||
|
}
|
||||||
|
|
||||||
config := &container.Config{
|
config := &container.Config{
|
||||||
Image: image,
|
Image: image,
|
||||||
Env: env,
|
Env: env,
|
||||||
@@ -212,6 +218,7 @@ func deployWorker(image string, identifier string, env []string) {
|
|||||||
//}
|
//}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[INFO] Container %s was created under environment %s", cont.ID, environment)
|
log.Printf("[INFO] Container %s was created under environment %s", cont.ID, environment)
|
||||||
|
//workerIds = append(workerIds, cont.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -248,7 +255,7 @@ func initializeImages() {
|
|||||||
log.Printf("[WARNING] SHUFFLE_APP_SDK_VERSION not defined. Defaulting to %s", appSdkVersion)
|
log.Printf("[WARNING] SHUFFLE_APP_SDK_VERSION not defined. Defaulting to %s", appSdkVersion)
|
||||||
}
|
}
|
||||||
if workerVersion == "" {
|
if workerVersion == "" {
|
||||||
workerVersion = "0.8.52"
|
workerVersion = "0.8.53"
|
||||||
log.Printf("[WARNING] SHUFFLE_WORKER_VERSION not defined. Defaulting to %s", workerVersion)
|
log.Printf("[WARNING] SHUFFLE_WORKER_VERSION not defined. Defaulting to %s", workerVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,6 +506,7 @@ func main() {
|
|||||||
fmt.Sprintf("EXECUTIONID=%s", execution.ExecutionId),
|
fmt.Sprintf("EXECUTIONID=%s", execution.ExecutionId),
|
||||||
fmt.Sprintf("ENVIRONMENT_NAME=%s", environment),
|
fmt.Sprintf("ENVIRONMENT_NAME=%s", environment),
|
||||||
fmt.Sprintf("BASE_URL=%s", baseUrl),
|
fmt.Sprintf("BASE_URL=%s", baseUrl),
|
||||||
|
fmt.Sprintf("CLEANUP=%s", cleanupEnv),
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.ToLower(os.Getenv("SHUFFLE_PASS_WORKER_PROXY")) != "false" {
|
if strings.ToLower(os.Getenv("SHUFFLE_PASS_WORKER_PROXY")) != "false" {
|
||||||
@@ -512,7 +520,7 @@ func main() {
|
|||||||
|
|
||||||
go deployWorker(workerImage, containerName, env)
|
go deployWorker(workerImage, containerName, env)
|
||||||
|
|
||||||
log.Printf("[INFO] %s was deployed and to be removed from queue.", execution.ExecutionId)
|
log.Printf("[INFO] ExecutionID %s was deployed and to be removed from queue.", execution.ExecutionId)
|
||||||
zombiecounter += 1
|
zombiecounter += 1
|
||||||
toBeRemoved.Data = append(toBeRemoved.Data, execution)
|
toBeRemoved.Data = append(toBeRemoved.Data, execution)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
NAME=shuffle-worker
|
NAME=shuffle-worker
|
||||||
VERSION=0.8.52
|
VERSION=0.8.53
|
||||||
|
|
||||||
echo "Running docker build with $NAME:$VERSION"
|
echo "Running docker build with $NAME:$VERSION"
|
||||||
#CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker.bin .
|
#CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker.bin .
|
||||||
@@ -10,5 +10,5 @@ docker build . -t frikky/shuffle:$NAME -t frikky/shuffle:$NAME_$VERSION -t docke
|
|||||||
#docker push frikky/shuffle:$NAME_$VERSION
|
#docker push frikky/shuffle:$NAME_$VERSION
|
||||||
#docker push docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION
|
#docker push docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION
|
||||||
#docker tag frikky/shuffle:0.8.51 ghcr.io/frikky/shuffle-worker:0.8.5
|
#docker tag frikky/shuffle:0.8.51 ghcr.io/frikky/shuffle-worker:0.8.5
|
||||||
#docker push ghcr.io/frikky/$NAME:$VERSION
|
|
||||||
docker tag frikky/shuffle:$NAME ghcr.io/frikky/shuffle-worker:0.8.52
|
docker tag frikky/shuffle:$NAME ghcr.io/frikky/shuffle-worker:0.8.52
|
||||||
|
docker push ghcr.io/frikky/$NAME:$VERSION
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
var environment = os.Getenv("ENVIRONMENT_NAME")
|
var environment = os.Getenv("ENVIRONMENT_NAME")
|
||||||
var baseUrl = os.Getenv("BASE_URL")
|
var baseUrl = os.Getenv("BASE_URL")
|
||||||
var appCallbackUrl = os.Getenv("BASE_URL")
|
var appCallbackUrl = os.Getenv("BASE_URL")
|
||||||
|
var cleanupEnv = strings.ToLower(os.Getenv("CLEANUP"))
|
||||||
var baseimagename = "frikky/shuffle"
|
var baseimagename = "frikky/shuffle"
|
||||||
var registryName = "registry.hub.docker.com"
|
var registryName = "registry.hub.docker.com"
|
||||||
var fallbackName = "shuffle-orborus"
|
var fallbackName = "shuffle-orborus"
|
||||||
@@ -43,6 +44,7 @@ var children map[string][]string
|
|||||||
var visited []string
|
var visited []string
|
||||||
var executed []string
|
var executed []string
|
||||||
var nextActions []string
|
var nextActions []string
|
||||||
|
var containerIds []string
|
||||||
var extra int
|
var extra int
|
||||||
var startAction string
|
var startAction string
|
||||||
|
|
||||||
@@ -68,9 +70,9 @@ func getThisContainerId() string {
|
|||||||
func init() {
|
func init() {
|
||||||
containerId = getThisContainerId()
|
containerId = getThisContainerId()
|
||||||
if len(containerId) == 0 {
|
if len(containerId) == 0 {
|
||||||
log.Printf("[ERROR] No container ID found. Not running containerized?")
|
log.Printf("[WARNING] No container ID found. Not running containerized? This should only show during testing")
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[INFO] Found container ID: %s", containerId)
|
log.Printf("[INFO] Found container ID for this worker: %s", containerId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,35 +772,28 @@ type AppExecutionExample struct {
|
|||||||
|
|
||||||
// removes every container except itself (worker)
|
// removes every container except itself (worker)
|
||||||
func shutdown(executionId, workflowId string) {
|
func shutdown(executionId, workflowId string) {
|
||||||
dockercli, err := dockerclient.NewEnvClient()
|
log.Printf("[INFO] Shutdown started")
|
||||||
if err != nil {
|
|
||||||
log.Printf("[ERROR] Unable to create docker client: %s", err)
|
|
||||||
os.Exit(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
containerOptions := types.ContainerListOptions{
|
// Might not be necessary because of cleanupEnv hostconfig autoremoval
|
||||||
All: true,
|
if cleanupEnv == "true" && len(containerIds) > 0 {
|
||||||
}
|
ctx := context.Background()
|
||||||
|
dockercli, err := dockerclient.NewEnvClient()
|
||||||
|
if err == nil {
|
||||||
|
log.Printf("[INFO] Cleaning up %d containers", len(containerIds))
|
||||||
|
removeOptions := types.ContainerRemoveOptions{
|
||||||
|
RemoveVolumes: true,
|
||||||
|
Force: true,
|
||||||
|
}
|
||||||
|
|
||||||
containers, err := dockercli.ContainerList(context.Background(), containerOptions)
|
for _, containername := range containerIds {
|
||||||
if err != nil {
|
log.Printf("[INFO] Stopping and removing container %s", containername)
|
||||||
panic(err)
|
dockercli.ContainerStop(ctx, containername, nil)
|
||||||
}
|
dockercli.ContainerRemove(ctx, containername, removeOptions)
|
||||||
_ = containers
|
//removeContainers = append(removeContainers, containername)
|
||||||
|
|
||||||
for _, container := range containers {
|
|
||||||
for _, name := range container.Names {
|
|
||||||
if strings.Contains(name, executionId) {
|
|
||||||
// FIXME - reinstate - not here for debugging
|
|
||||||
//err = removeContainer(container.ID)
|
|
||||||
//if err != nil {
|
|
||||||
// log.Printf("Failed removing %s before shutdown.", name)
|
|
||||||
//}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("[INFO] NOT cleaning up containers. IDS: %d, CLEANUP env: %s", len(containerIds), cleanupEnv)
|
||||||
}
|
}
|
||||||
|
|
||||||
fullUrl := fmt.Sprintf("%s/api/v1/workflows/%s/executions/%s/abort", baseUrl, workflowId, executionId)
|
fullUrl := fmt.Sprintf("%s/api/v1/workflows/%s/executions/%s/abort", baseUrl, workflowId, executionId)
|
||||||
@@ -844,7 +839,9 @@ func shutdown(executionId, workflowId string) {
|
|||||||
log.Printf("[INFO] Failed abort request: %s", err)
|
log.Printf("[INFO] Failed abort request: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] Finished shutdown.")
|
log.Printf("[INFO] Finished shutdown (after 15 seconds).")
|
||||||
|
// Allows everything to finish in subprocesses
|
||||||
|
time.Sleep(time.Duration(15) * time.Second)
|
||||||
os.Exit(3)
|
os.Exit(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,6 +862,10 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
|
|||||||
log.Printf("[WARNING] Empty self container id, continue without NetworkMode")
|
log.Printf("[WARNING] Empty self container id, continue without NetworkMode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cleanupEnv == "true" {
|
||||||
|
hostConfig.AutoRemove = true
|
||||||
|
}
|
||||||
|
|
||||||
config := &container.Config{
|
config := &container.Config{
|
||||||
Image: image,
|
Image: image,
|
||||||
Env: env,
|
Env: env,
|
||||||
@@ -892,6 +893,7 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] Container %s is created for %s", cont.ID, identifier)
|
log.Printf("[INFO] Container %s is created for %s", cont.ID, identifier)
|
||||||
|
containerIds = append(containerIds, cont.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1537,71 +1539,16 @@ func handleExecutionResult(workflowExecution WorkflowExecution) {
|
|||||||
|
|
||||||
// FIXME - new request here
|
// FIXME - new request here
|
||||||
// FIXME - clean up stopped (remove) containers with this execution id
|
// FIXME - clean up stopped (remove) containers with this execution id
|
||||||
dockercli, err := dockerclient.NewEnvClient()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Unable to create docker client: %s", err)
|
|
||||||
shutdown(workflowExecution.ExecutionId, workflowExecution.Workflow.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(workflowExecution.Results) == len(workflowExecution.Workflow.Actions)+extra {
|
if len(workflowExecution.Results) == len(workflowExecution.Workflow.Actions)+extra {
|
||||||
shutdownCheck := true
|
shutdownCheck := true
|
||||||
ctx := context.Background()
|
|
||||||
for _, result := range workflowExecution.Results {
|
for _, result := range workflowExecution.Results {
|
||||||
if result.Status == "EXECUTING" {
|
if result.Status == "EXECUTING" {
|
||||||
// Cleaning up executing stuff
|
// Cleaning up executing stuff
|
||||||
shutdownCheck = false
|
shutdownCheck = false
|
||||||
// Check status
|
// USED TO BE CONTAINER REMOVAL
|
||||||
containers, err := dockercli.ContainerList(ctx, types.ContainerListOptions{
|
|
||||||
All: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed listing containers: %s", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
stopContainers := []string{}
|
|
||||||
removeContainers := []string{}
|
|
||||||
for _, container := range containers {
|
|
||||||
for _, name := range container.Names {
|
|
||||||
if !strings.Contains(name, result.Action.ID) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if container.State != "running" {
|
|
||||||
removeContainers = append(removeContainers, container.ID)
|
|
||||||
stopContainers = append(stopContainers, container.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME - add killing of apps with same execution ID too
|
|
||||||
// FIXME - stahp
|
|
||||||
//for _, containername := range stopContainers {
|
|
||||||
// if err := dockercli.ContainerStop(ctx, containername, nil); err != nil {
|
|
||||||
// log.Printf("Unable to stop container: %s", err)
|
|
||||||
// } else {
|
|
||||||
// log.Printf("Stopped container %s", containername)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
removeOptions := types.ContainerRemoveOptions{
|
|
||||||
RemoveVolumes: true,
|
|
||||||
Force: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = removeOptions
|
|
||||||
|
|
||||||
// FIXME - this
|
|
||||||
//for _, containername := range removeContainers {
|
|
||||||
// if err := dockercli.ContainerRemove(ctx, containername, removeOptions); err != nil {
|
|
||||||
// log.Printf("Unable to remove container: %s", err)
|
|
||||||
// } else {
|
|
||||||
// log.Printf("Removed container %s", containername)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
// FIXME - send POST request to kill the container
|
// FIXME - send POST request to kill the container
|
||||||
log.Printf("Should remove (POST request) stopped containers")
|
//log.Printf("Should remove (POST request) stopped containers")
|
||||||
//ret = requests.post("%s%s" % (self.url, stream_path), headers=headers, json=action_result)
|
//ret = requests.post("%s%s" % (self.url, stream_path), headers=headers, json=action_result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2511,7 +2458,7 @@ func validateFinished(workflowExecution WorkflowExecution) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Failed reading body: %s", err)
|
log.Printf("[ERROR] Failed reading body: %s", err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("NEWRESP: %s", string(body))
|
log.Printf("[INFO] NEWRESP (from backend): %s", string(body))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2583,7 +2530,7 @@ func setWorkflowExecution(ctx context.Context, workflowExecution WorkflowExecuti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetLocalIP returns the non loopback local IP of the host
|
// GetLocalIP returns the non loopback local IP of the host
|
||||||
func GetLocalIP() string {
|
func getLocalIP() string {
|
||||||
addrs, err := net.InterfaceAddrs()
|
addrs, err := net.InterfaceAddrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
@@ -2599,22 +2546,46 @@ func GetLocalIP() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func webserverSetup() {
|
func getAvailablePort() (net.Listener, error) {
|
||||||
hostname := GetLocalIP()
|
listener, err := net.Listen("tcp", ":0")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[WARNING] Failed to assign port by default. Defaulting to 5001")
|
||||||
|
//return ":5001"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("\nStarting webserver on port 5001 with hostname: %s\n", hostname)
|
return listener, nil
|
||||||
log.Printf("OLD HOSTNAME: %s", appCallbackUrl)
|
//return fmt.Sprintf(":%d", port)
|
||||||
appCallbackUrl = fmt.Sprintf("http://%s:5001", hostname)
|
|
||||||
log.Printf("NEW HOSTNAME: %s", appCallbackUrl)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWebserver() {
|
func webserverSetup(workflowExecution WorkflowExecution) net.Listener {
|
||||||
|
hostname := getLocalIP()
|
||||||
|
|
||||||
|
// FIXME: This MAY not work because of speed between first
|
||||||
|
// container being launched and port being assigned to webserver
|
||||||
|
listener, err := getAvailablePort()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to created listener: %s", err)
|
||||||
|
shutdown(workflowExecution.ExecutionId, workflowExecution.Workflow.ID)
|
||||||
|
}
|
||||||
|
port := listener.Addr().(*net.TCPAddr).Port
|
||||||
|
|
||||||
|
log.Printf("\n\nStarting webserver on port %d with hostname: %s\n\n", port, hostname)
|
||||||
|
log.Printf("OLD HOSTNAME: %s", appCallbackUrl)
|
||||||
|
appCallbackUrl = fmt.Sprintf("http://%s:%d", hostname, port)
|
||||||
|
log.Printf("NEW HOSTNAME: %s", appCallbackUrl)
|
||||||
|
|
||||||
|
return listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func runWebserver(listener net.Listener) {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/api/v1/streams", handleWorkflowQueue).Methods("POST")
|
r.HandleFunc("/api/v1/streams", handleWorkflowQueue).Methods("POST")
|
||||||
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
|
||||||
http.Handle("/", r)
|
http.Handle("/", r)
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(":5001", nil))
|
//log.Fatal(http.ListenAndServe(port, nil))
|
||||||
|
log.Fatal(http.Serve(listener, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial loop etc
|
// Initial loop etc
|
||||||
@@ -2735,8 +2706,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Environments: %s. 1 = webserver, 0 or >1 = default", environments)
|
log.Printf("Environments: %s. 1 = webserver, 0 or >1 = default", environments)
|
||||||
if len(environments) == 1 {
|
if len(environments) == 1 { //&& len(workflowExecution.Actions)+len(workflowExecution.Triggers) > 1 {
|
||||||
webserverSetup()
|
listener := webserverSetup(workflowExecution)
|
||||||
err := executionInit(workflowExecution)
|
err := executionInit(workflowExecution)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
|
log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
|
||||||
@@ -2748,7 +2719,7 @@ func main() {
|
|||||||
handleExecutionResult(workflowExecution)
|
handleExecutionResult(workflowExecution)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
runWebserver()
|
runWebserver(listener)
|
||||||
//log.Printf("Before wait")
|
//log.Printf("Before wait")
|
||||||
//wg := sync.WaitGroup{}
|
//wg := sync.WaitGroup{}
|
||||||
//wg.Add(1)
|
//wg.Add(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user