func (st *worker) setupInternalFunctionOperations() {
	st.setInternalFunctionForAction([]string{actionKillWorker, actionLateKillWorker}, func() bool {
		return false
	})
}
*************************************************************************************************************
** Internal action operations  ******************************************************************************
*************************************************************************************************************
package goworkerpool
import (
	"fmt"
	"sync"
	"time"
	"github.com/enriquebris/goconcurrentcounter"
)
const (
	ErrorWorkerNilTask    = "worker.nil.task"
	ErrorWorkerNoTaskFunc = "worker.no.func.to.process.task"
	ListenInProgress      = "listen.in.progress"
	WorkerClosed          = "worker.closed"
)
type (
	workerExternalActionFunc func() (reEnqueueWorker bool)
	workerInternalActionFunc func() bool
	workerFeedbackFunc func(wkrID int, reEnqueueWorker bool)
	workerExternalGeneralFunc func()
	workerExternalFailFunc func(tsk *task, err error)
)
type workerFeedback struct {
	workerID        int
	reEnqueueWorker bool
}
type workerFunctionData struct {
	result bool
	err    error
}
type worker struct {
	id          int
	tasksChan   chan *task
	actionsChan chan action
	closeChan chan chan struct{}
	closeListenChan chan struct{}
	internalActions map[string]workerInternalActionFunc
	externalActions map[string]workerExternalActionFunc
	externalFeedbackFunc workerFeedbackFunc
	externalPreActionFunc workerExternalGeneralFunc
	externalPostActionFunc workerExternalGeneralFunc
	externalPreTaskFunc workerExternalGeneralFunc
	externalPostTaskFunc workerExternalGeneralFunc
	externalFailFunc workerExternalFailFunc
	errorChan chan *PoolError
	taskSuccesses         int
	externalTaskSuccesses goconcurrentcounter.Int
	taskFailures          int
	generalInfoMap sync.Map
}
func newWorker(id int) *worker {
	ret := &worker{}
	ret.initialize(id)
	return ret
}
func (st *worker) initialize(id int) {
	st.id = id
	st.tasksChan = make(chan *task)
	st.actionsChan = make(chan action)
	st.closeChan = make(chan chan struct{})
	st.closeListenChan = make(chan struct{})
	st.internalActions = make(map[string]workerInternalActionFunc)
	st.externalActions = make(map[string]workerExternalActionFunc)
	st.setStatus(WorkerClosed, false)
	st.setupInternalFunctionOperations()
}
func (st *worker) GetID() int {
	return st.id
}
func (st *worker) GetTasksChannel() chan *task {
	return st.tasksChan
}
func (st *worker) GetActionsChannel() chan action {
	return st.actionsChan
}
func (st *worker) Close() chan struct{} {
	waitingForListenDown := make(chan struct{})
	select {
	case st.closeChan <- waitingForListenDown:
		<-waitingForListenDown
	default:
		close(waitingForListenDown)
	}
	close(st.closeChan)
	close(st.GetTasksChannel())
	close(st.GetActionsChannel())
	st.setStatus(WorkerClosed, true)
	return st.closeListenChan
}
func (st *worker) SetErrorChannel(ch chan *PoolError) {
	st.errorChan = ch
}
func (st *worker) GetErrorChannel() chan *PoolError {
	return st.errorChan
}
func (st *worker) setInternalFunctionForAction(actionCodes []string, fn workerInternalActionFunc) {
	for _, actionCode := range actionCodes {
		st.internalActions[actionCode] = fn
	}
}
func (st *worker) SetExternalTaskSuccesses(external goconcurrentcounter.Int) {
	st.externalTaskSuccesses = external
}
func (st *worker) GetExternalTaskSuccesses() goconcurrentcounter.Int {
	return st.externalTaskSuccesses
}
func (st *worker) SetExternalFunctionForAction(actionCode string, fn workerExternalActionFunc) {
	st.externalActions[actionCode] = fn
}
func (st *worker) SetExternalFeedbackFunction(fn workerFeedbackFunc) {
	st.externalFeedbackFunc = fn
}
func (st *worker) SetExternalPreActionFunc(fn workerExternalGeneralFunc) {
	st.externalPreActionFunc = fn
}
func (st *worker) SetExternalPostActionFunc(fn workerExternalGeneralFunc) {
	st.externalPostActionFunc = fn
}
func (st *worker) SetExternalPreTaskFunc(fn workerExternalGeneralFunc) {
	st.externalPreTaskFunc = fn
}
func (st *worker) SetExternalPostTaskFunc(fn workerExternalGeneralFunc) {
	st.externalPostTaskFunc = fn
}
func (st *worker) SetExternalFailFunc(fn workerExternalFailFunc) {
	st.externalFailFunc = fn
}
func (st *worker) GetExternalFailFunc() workerExternalFailFunc {
	return st.externalFailFunc
}
func (st *worker) ProcessTask(tsk *task) error {
	if tsk == nil {
		return newPoolError(ErrorWorkerNilTask, "nil task was received by the worker")
	}
	if tsk.Code == taskRegular && tsk.Func == nil && tsk.CallbackFunc == nil {
		return newPoolError(ErrorWorkerNoTaskFunc, "No function provided to process the task")
	}
	st.tasksChan <- tsk
	return nil
}
func (st *worker) ProcessAction(actn action) {
	st.actionsChan <- actn
}
func (st *worker) Listen() {
	if !st.getStatus(ListenInProgress) {
		go func() {
			var (
				keepWorking                 = true
				reEnqueueWorker             = true
				isAction                    = false
				isTask                      = false
				executeExternalFeedbackFunc = true
			)
			st.setStatus(ListenInProgress, true)
			for keepWorking {
				isAction = false
				isTask = false
				executeExternalFeedbackFunc = true
				select {
				case closeChan := <-st.closeChan:
					keepWorking = false
					executeExternalFeedbackFunc = false
					defer func() { closeChan <- struct{}{} }()
				case actn := <-st.actionsChan:
					isAction = true
					if st.externalPreActionFunc != nil {
						st.externalPreActionFunc()
					}
					if internalFunc, ok := st.internalActions[actn.Code]; ok {
						keepWorking = internalFunc()
					}
					if externalFunc, ok := st.externalActions[actn.Code]; ok {
						reEnqueueWorker = externalFunc()
					}
				case tsk := <-st.tasksChan:
					if tsk == nil {
						keepWorking = false
						break
					}
					isTask = true
					switch tsk.Code {
					case taskRegular:
						if st.externalPreTaskFunc != nil {
							st.externalPreTaskFunc()
						}
						var success bool
						if tsk.Func != nil {
							resultChan := make(chan workerFunctionData, 2)
							st.executeFunction(tsk.Func, tsk.Data, resultChan, 0)
							result := <-resultChan
							if result.err == nil {
								success = result.result
							} else {
								if st.GetExternalFailFunc() != nil {
									st.GetExternalFailFunc()(tsk, result.err)
								}
								success = false
							}
							if success {
								st.taskSuccesses++
								if st.externalTaskSuccesses != nil {
									st.externalTaskSuccesses.Update(1)
								}
							} else {
								st.taskFailures++
							}
						}
						if tsk.CallbackFunc != nil {
							tsk.CallbackFunc(tsk.Data)
						}
					case taskLateAction:
						actn, _ := tsk.Data.(action)
						isAction = true
						isTask = false
						if st.externalPreActionFunc != nil {
							st.externalPreActionFunc()
						}
						if internalFunc, ok := st.internalActions[actn.Code]; ok {
							keepWorking = internalFunc()
						}
						if externalFunc, ok := st.externalActions[actn.Code]; ok {
							reEnqueueWorker = externalFunc()
						}
					}
				}
				if !keepWorking {
					reEnqueueWorker = false
				}
				if executeExternalFeedbackFunc && st.externalFeedbackFunc != nil {
					st.externalFeedbackFunc(st.GetID(), reEnqueueWorker)
				}
				if isAction && st.externalPostActionFunc != nil {
					st.externalPostActionFunc()
					continue
				}
				if isTask && st.externalPostTaskFunc != nil {
					st.externalPostTaskFunc()
					continue
				}
			}
			st.setStatus(ListenInProgress, false)
			select {
			case st.closeListenChan <- struct{}{}:
			default:
			}
		}()
	}
}
func (st *worker) executeFunction(fn PoolFunc, data interface{}, resultChan chan workerFunctionData, maxDuration time.Duration) {
	defer func() {
		if r := recover(); r != nil {
			resultChan <- workerFunctionData{
				result: false,
				err:    newPoolError(ErrorWorkerFuncPanic, fmt.Sprintf("%v", r)),
			}
		}
	}()
	if maxDuration == 0 {
		resultChan <- workerFunctionData{
			result: fn(data),
			err:    nil,
		}
	} else {
		doneChan := make(chan bool)
		go func(fn PoolFunc, data interface{}, doneChan chan bool) {
			doneChan <- fn(data)
		}(fn, data, doneChan)
		select {
		case result := <-doneChan:
			resultChan <- workerFunctionData{
				result: result,
				err:    nil,
			}
		case <-time.After(maxDuration):
			resultChan <- workerFunctionData{
				result: false,
				err:    newPoolError(ErrorWorkerMaxTimeExceeded, "Function exceeded max execution time"),
			}
		}
	}
}
func (st *worker) GetTaskSuccesses() int {
	return st.taskSuccesses
}
func (st *worker) GetTaskFailures() int {
	return st.taskFailures
}
func (st *worker) setStatus(operationName string, status bool) {
	st.generalInfoMap.Store(operationName, status)
}
func (st *worker) getStatus(operationName string) bool {
	rawValue, ok := st.generalInfoMap.Load(operationName)
	if !ok {
		return false
	}
	value := rawValue.(bool)
	return value
}
func (st *worker) Closed() bool {
	return st.getStatus(WorkerClosed)
}