<reponame>bellanov/calculator
"""
Daemon Threads.

Various examples exhibiting Thread use.
"""
from threading import Thread
from threading import current_thread
import logging
import os
import random
import time

# Environment
ENV = os.environ.get("ENV") or "development"
LOG_LEVEL = os.environ.get("LOG_LEVEL") or "info"

# Configuration
DELAY = os.environ.get("DELAY") or "2"

# Logging
loggers = {"debug": logging.DEBUG, "info": logging.INFO, "error": logging.ERROR}
logging.basicConfig(level=loggers[LOG_LEVEL], format="%(asctime)-15s %(levelname)-8s %(message)s")
logger = logging.getLogger("daemon")

logger.debug("Configuration...")
logger.debug("Environment => {}".format(ENV))
logger.debug("LOG LEVEL => {}".format(LOG_LEVEL))
logger.debug("DELAY => {} seconds".format(DELAY))

current_thread().setName("parent")


def job1():
    """Simulate Job."""
    logger.info("Job 1 Execution / id: {} /".format(current_thread().ident))

    for _ in range(10):

        # Simulate Task
        time.sleep(random.randint(0, int(DELAY)))
        logger.info(
            "{} => Checking In [ daemon: {} ] [ id: {} ]".format(
                current_thread().getName(), current_thread().isDaemon(), current_thread().ident
            )
        )

        # Start Embedded Thread
        # Halts when parent thread execution completes
        t2 = Thread(target=job2, name="child-2")
        t2.start()


def job2():
    """Simulate Support Job."""
    logger.info("Job 2 Execution / id: {} /".format(current_thread().ident))

    # Simulate Support Task
    for _ in range(5):
        logger.info(
            "{} => Checking In [ daemon: {} ] [ id: {} ]".format(
                current_thread().getName(), current_thread().isDaemon(), current_thread().ident
            )
        )


# Start Time
start_time = time.time()

# Start Thread
t1 = Thread(target=job1, name="child-1", daemon=True)
t1.start()

# Simulate Task in Main Thread
for i in range(15):
    logger.info("{} => Checking In [ daemon: {} ]".format(current_thread().getName(), current_thread().isDaemon()))
    time.sleep(random.randint(0, int(DELAY)))

# End of Main Flow
# Once execution ends, all Daemon threads are subsequently halted
logger.info("Operation COMPLETE!!!")

# End Time
end_time = time.time()
total_time = end_time - start_time

logger.info("Total Time: {}".format(total_time))

# Summary
#
# Before Daemonization, child thread continues to execute after main flow is completed
#
# 2021-04-25 04:28:14,324 INFO     Operation COMPLETE!!!
# 2021-04-25 04:28:14,324 INFO     child-2 => Checking In [ daemon: False ] [ id: 123145468506112 ]
# 2021-04-25 04:28:14,325 INFO     Total Time: 13.02090072631836
# 2021-04-25 04:28:14,325 INFO     child-2 => Checking In [ daemon: False ] [ id: 123145468506112 ]
# 2021-04-25 04:28:14,325 INFO     child-2 => Checking In [ daemon: False ] [ id: 123145468506112 ]


# Otherwise, everything will run concurrently, which breaks any dependency
# 2021-04-25 04:31:07,310 INFO     parent => Checking In [ daemon: False ]
# 2021-04-25 04:31:09,310 INFO     parent => Checking In [ daemon: False ]
# 2021-04-25 04:31:11,311 INFO     parent => Checking In [ daemon: False ]
# 2021-04-25 04:31:13,312 INFO     Operation COMPLETE!!!
# 2021-04-25 04:31:13,312 INFO     Total Time: 21.015228986740112
