Permalink
Browse files

improve UX of a provisioning script execution with more detailed stat…

…us messages
  • Loading branch information...
Stanislav Tiurikov
Stanislav Tiurikov committed Oct 8, 2017
1 parent 9c1604b commit ebbbc009c7fe4e9e9a09753454dfa7915088faf2
View
BIN -4 Bytes (100%) gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
@@ -64,9 +64,11 @@ class ConsoleLogger {
def static synchronized updateStatus() {
if (enableDynamics) {
statusLoggers.each {
statusPrinted++
println(Ansi.ansi().cursorToColumn(0).eraseLine(Ansi.Erase.FORWARD).bold().fg(DEFAULT).a(it.statusLine()).reset())
statusLoggers.each { logger ->
logger.statusLine().eachLine { line ->
statusPrinted++
println(Ansi.ansi().cursorToColumn(0).eraseLine(Ansi.Erase.FORWARD).bold().fg(DEFAULT).a(line).reset())
}
}
}
}
@@ -0,0 +1,52 @@
package io.infrastructor.core.logging.status
import static io.infrastructor.core.logging.ConsoleLogger.*
class TaskProgressLogger {
def name = ''
def nodes = [:].asSynchronized()
def listener = {}
def progress = 0
def synchronized increase() {
progress++
listener()
}
def updateStatus(def nodeName, def status) {
nodes[nodeName] = status
listener()
}
public String statusLine() {
def status = new StringBuilder()
status << "> task: '$name', progress: $progress / ${nodes.size()} node|s" << "\n"
nodes.each { node, nodeStatus ->
status << " node: '$node' - $nodeStatus" << "\n"
}
status << " -----" << "\n"
return status
}
public static void withTaskProgressStatus(def name, Closure closure) {
debug "withTaskProgressStatus: $name "
def logger = new TaskProgressLogger(name: name)
try {
debug "addStatusLogger: $name "
addStatusLogger logger
debug "addStatusLogger:run: $name "
closure(logger)
} catch(Throwable t) {
t.printStackTrace()
println "withTaskProgressStatus: $t"
} finally {
debug "addStatusLogger:removeStatusLogger: $name "
removeStatusLogger logger
}
}
}
@@ -9,6 +9,7 @@ import java.util.concurrent.atomic.AtomicInteger
import static io.infrastructor.core.logging.ConsoleLogger.*
import static io.infrastructor.core.logging.status.TextStatusLogger.withTextStatus
import static io.infrastructor.core.logging.status.ProgressStatusLogger.withProgressStatus
import static io.infrastructor.core.logging.status.TaskProgressLogger.withTaskProgressStatus
import static io.infrastructor.core.processing.ProvisioningContext.provision
import static io.infrastructor.core.utils.ParallelUtils.executeParallel
@@ -18,45 +19,45 @@ class Task {
def parallel = 1
def actions = {}
def onSuccess = {}
def onFailure = {
throw new TaskExecutionException(":task '$name' - failed on ${context.failed.size()} node|s")
}
def onFailure = { throw new TaskExecutionException(":task '$name' - failed on ${context.failed.size()} node|s") }
def execute(def nodes) {
def filtered = filter ? nodes.findAll { FilteringUtils.match(it.listTags(), filter) } : nodes
info "${blue(":task '${name}'")}"
info "${blue("> task: '${name}'")}"
def failedNodes = [].asSynchronized()
withTextStatus { statusLine ->
withProgressStatus(filtered.size(), 'nodes processed') { progressLine ->
executeParallel(filtered, parallel) { node ->
try {
statusLine "> task: $name"
new NodeContext(node: node).with(actions.clone())
} catch (ActionExecutionException ex) {
error "FAILED - node.id: $node.id, $ex.message"
failedNodes << node
} catch(Exception ex) {
error "FAILED - node.id: $node.id, message: $ex.message"
failedNodes << node
} finally {
progressLine.increase()
node.disconnect()
}
withTaskProgressStatus(name) { status ->
filtered.each { status.updateStatus(it.id, 'waiting') }
executeParallel(filtered, parallel) { node ->
try {
status.updateStatus(node.id, "${blue("running")}")
new NodeContext(node: node).with(actions.clone())
status.updateStatus(node.id, "${green("done")}")
} catch (ActionExecutionException ex) {
error "FAILED - node.id: $node.id, $ex.message"
failedNodes << node
status.updateStatus(node.id, "${red("falied")}")
} catch(Exception ex) {
error "FAILED - node.id: $node.id, message: $ex.message"
failedNodes << node
status.updateStatus(node.id, "${red("falied")}")
} finally {
status.increase()
node.disconnect()
}
}
}
// determine if we can go to the next task or we should stop the execution
if (failedNodes.size() > 0) {
provision(nodes, [failed: failedNodes], onFailure)
} else {
provision(nodes, onSuccess)
}
info "${blue(":task '$name' - done")}"
info "${blue("> task: '$name', done on ${filtered.size()} node|s")}"
}
}

0 comments on commit ebbbc00

Please sign in to comment.