Skip to content
Open
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ The interface consists of four public functions and one variable that reports ho
# \brief initializes the job pool
# \param[in] pool_size number of parallel jobs allowed
# \param[in] echo_command 1 to turn on echo, 0 to turn off
# \param[in] job_pool_function_pre_job (optional) a function that will be called before each job
# \param[in] job_pool_function_post_job (optional) a function that will be called after each job.
#
# To only have a post job function, the given parameter for the pre job function should be: "".
function job_pool_init()

# \brief waits for all queued up jobs to complete and shuts down the job pool
Expand All @@ -65,6 +69,8 @@ The interface consists of four public functions and one variable that reports ho

This was inspired by [a discussion on StackOverflow](http://stackoverflow.com/questions/6441509/how-to-write-a-process-pool-bash-shell).

For more information on the parameters "job_pool_function_pre_job" and "job_pool_function_post_job" of the "job_pool_init" function, check the sample program "job_pool_sample_injected_functions.sh".

## `genpass.sh`
`genpass.sh` is a random password generator, it will produce a random password of the desired length which is suitable
for manual entering via the keyboard.
Expand Down
22 changes: 22 additions & 0 deletions job_pool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ job_pool_pool_size=-1
# \brief variable to check for number of non-zero exits
job_pool_nerrors=0

# function that will be called before each job. By default, no function is called.
job_pool_function_pre_job=""

# function that will be called after each job. By default, no function is called.
job_pool_function_post_job=""

################################################################################
# private functions
################################################################################
Expand Down Expand Up @@ -106,6 +112,11 @@ function _job_pool_worker()
# will know we are exiting.
echo "${cmd}" >&7
else
# run the pre job injected function if it was provided
if [[ "${job_pool_function_pre_job}" != "" ]]; then
"${job_pool_function_pre_job}"
fi

_job_pool_echo "### _job_pool_worker-${id}: ${cmd}"
# run the job
{ ${cmd} "$@" ; }
Expand All @@ -124,6 +135,11 @@ function _job_pool_worker()
flock --unlock 8
exec 8>&-
_job_pool_echo "### _job_pool_worker-${id}: exited ${result}: ${cmd} $@"

# run the post job injected function if it was provided
if [[ "${job_pool_function_post_job}" != "" ]]; then
"${job_pool_function_post_job}"
fi
fi
done
exec 7>&-
Expand Down Expand Up @@ -157,12 +173,18 @@ function _job_pool_start_workers()
# \brief initializes the job pool
# \param[in] pool_size number of parallel jobs allowed
# \param[in] echo_command 1 to turn on echo, 0 to turn off
# \param[in] job_pool_function_pre_job (optional) a function that will be called before each job
# \param[in] job_pool_function_post_job (optional) a function that will be called after each job.
#
# To only have a post job function, the given parameter for the pre job function should be: "".
function job_pool_init()
{
local pool_size=$1
local echo_command=$2

# set the global attibutes
job_pool_function_pre_job=$3
job_pool_function_post_job=$4
job_pool_pool_size=${pool_size:=1}
job_pool_echo_command=${echo_command:=0}

Expand Down
60 changes: 60 additions & 0 deletions job_pool_sample_injected_functions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash

. job_pool.sh

#####################################################
# Demonstration of function injection into each job #
#####################################################

echo "Demonstration of function injection into each job:"

# sleep some time ($1) then echo something ($2)
function sleep_n_echo()
{
sleep "$1"
echo "$2"
}

# Injected function that will be called before each job
#
# Print which worker is starting which job
function print_starting_job()
{
echo " # _job_pool_worker-${id}: Starting job: ${cmd} $(echo "${args[@]}" | xargs | tr '\v' ' ')"
}

# Injected function that will be called afetr each job
#
# Kill all workers if the local variable "result" from _job_pool_worker
# indicates that the job failed
function kill_workers()
{
echo " # _job_pool_worker-${id}: Finished job: ${cmd} $(echo "${args[@]}" | xargs | tr '\v' ' ')"

# result is undefined in this script, but will be defined when
# the function is injected in _job_pool_worker
if [[ "${result}" != "0" ]]; then
# get the pids of all workers:
# - each worker's process is named after the current script (here, job_pool_sample.sh),
# so we use this name to get the pids
# - we do not include the current script's pid ($$) as it is not a worker,
# (we do not want to kill the script itself, only the workers)
local workers_pids=("$(pgrep -f "$0" | grep -v $$)")
kill ${workers_pids[@]} &> /dev/null &
fi
}

# allow 3 parallel jobs, and kill all jobs at the first fail using "kill_workers" function
job_pool_init 3 0 print_starting_job kill_workers

# simulate 3 jobs, where one fails before the others are finished, and interrupts the others
job_pool_run sleep_n_echo 3 a # job 1
job_pool_run /bin/false # job 2
job_pool_run sleep_n_echo 3 b # job 3

# the job 2 will kill all other running workers, using the function "kill_workers"
# (that is ran after processing each job)

job_pool_shutdown

echo -e "\nOnly the failed job exited, the others did not because they were canceled."