# Buggy code
def start(self):
    self._shutdown = False

    eventlet.spawn(self.run)
    eventlet.spawn(self.cleanup)


# Traceback (NotMasterError)
2019-02-04 14:48:45,229 140516293681552 INFO scheduler [-] (PID=8536) Scheduler started.
2019-02-04 14:48:45,418 140516293681552 INFO consumers [-] Starting SchedulerEntrypoint...
2019-02-04 14:48:45,429 140516109106224 INFO mixins [-] Connected to amqp://xxx:**@127.0.0.1:5672//
2019-02-04 14:51:05,599 140516198248688 ERROR traceback [-] Traceback (most recent call last):

2019-02-04 14:51:05,599 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/eventlet/hubs/poll.py", line 109, in wait

2019-02-04 14:51:05,600 140516198248688 ERROR traceback [-]     listener.cb(fileno)

2019-02-04 14:51:05,600 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/eventlet/greenthread.py", line 219, in main

2019-02-04 14:51:05,600 140516198248688 ERROR traceback [-]     result = function(*args, **kwargs)

2019-02-04 14:51:05,600 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/st2actions/scheduler/handler.py", line 67, in run

2019-02-04 14:51:05,601 140516198248688 ERROR traceback [-]     execution_queue_item_db = self._get_next_execution()

2019-02-04 14:51:05,601 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/st2actions/scheduler/handler.py", line 125, in _get_next_execution

2019-02-04 14:51:05,601 140516198248688 ERROR traceback [-]     execution_queue_item_db = ActionExecutionSchedulingQueue.query(**query).first()

2019-02-04 14:51:05,601 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/mongoengine/queryset/base.py", line 294, in first

2019-02-04 14:51:05,602 140516198248688 ERROR traceback [-]     result = queryset[0]

2019-02-04 14:51:05,602 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/mongoengine/queryset/base.py", line 194, in __getitem__

2019-02-04 14:51:05,602 140516198248688 ERROR traceback [-]     queryset._cursor[key],

2019-02-04 14:51:05,602 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/pymongo/cursor.py", line 610, in __getitem__

2019-02-04 14:51:05,603 140516198248688 ERROR traceback [-]     for doc in clone:

2019-02-04 14:51:05,603 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/pymongo/cursor.py", line 1189, in next

2019-02-04 14:51:05,603 140516198248688 ERROR traceback [-]     if len(self.__data) or self._refresh():

2019-02-04 14:51:05,603 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/pymongo/cursor.py", line 1104, in _refresh

2019-02-04 14:51:05,603 140516198248688 ERROR traceback [-]     self.__send_message(q)

2019-02-04 14:51:05,604 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/pymongo/cursor.py", line 982, in __send_message

2019-02-04 14:51:05,604 140516198248688 ERROR traceback [-]     helpers._check_command_response(first)

2019-02-04 14:51:05,604 140516198248688 ERROR traceback [-]   File "/opt/stackstorm/st2/lib/python2.7/site-packages/pymongo/helpers.py", line 132, in _check_command_response

2019-02-04 14:51:05,604 140516198248688 ERROR traceback [-]     raise NotMasterError(errmsg, response)

2019-02-04 14:51:05,604 140516198248688 ERROR traceback [-] NotMasterError: interrupted at shutdown

2019-02-04 14:51:05,605 140516198248688 ERROR hub [-] Removing descriptor: 9

2019-02-05 03:28:30,413 140516198248688 INFO misc [-] Re-opening log file "/var/log/st2/st2scheduler.log" with mode "a"

2019-02-05 03:28:30,422 140516198248688 INFO misc [-] Re-opening log file "/var/log/st2/st2scheduler.audit.log" with mode "a"

# Fixed code
def start(self):
    self._shutdown = False

    # Spawn the worker threads.
    self._main_thread = eventlet.spawn(self.run)
    self._cleanup_thread = eventlet.spawn(self.cleanup)

    # Link the threads to the shutdown function. If either of the threads exited with error,
    # then initiate shutdown which will allow the waits below to throw exception to the
    # main process.
    self._main_thread.link(self.shutdown)
    self._cleanup_thread.link(self.shutdown)