# Buggy code
def consume_events(self):
    # discover new events and ingest them
    events_path = self.path_to("artifacts", self.ident, "job_events")

    # it's possible that `events_path` doesn't exist *yet*, because runner
    # hasn't actually written any events yet (if you ran e.g., a sleep 30)
    # only attempt to consume events if any were rsynced back
    if os.path.exists(events_path):
        for event in set(os.listdir(events_path)) - self.handled_events:
            path = os.path.join(events_path, event)
            if os.path.exists(path):
                try:
                    event_data = json.load(open(os.path.join(events_path, event), "r"))
                except json.decoder.JSONDecodeError:
                    # This means the event we got back isn't valid JSON
                    # that can happen if runner is still partially
                    # writing an event file while it's rsyncing
                    # these event writes are _supposed_ to be atomic
                    # but it doesn't look like they actually are in
                    # practice
                    # in this scenario, just ignore this event and try it
                    # again on the next sync
                    pass
                self.event_handler(event_data)
                self.handled_events.add(event)


# Traceback (IsADirectoryError)
2020-03-12 23:43:10,040 ERROR    awx.isolated.manager.playbooks
PLAY [Poll for status of active job.] ******************************************

TASK [Determine if daemon process is alive.] ***********************************
changed: [awx-job-164]

TASK [Copy artifacts from the isolated host.] **********************************
skipping: [awx-job-164]

TASK [Copy daemon log from the isolated host] **********************************
skipping: [awx-job-164]

TASK [Copy artifacts from pod] *************************************************

2020-03-12 23:43:10,042 ERROR    awx.main.tasks job 164 (running) Exception occurred while running task
Traceback (most recent call last):
File "/var/lib/awx/venv/awx/lib/python3.6/site-packages/awx/main/tasks.py", line 1401, in run
ident=str(self.instance.pk))
File "/var/lib/awx/venv/awx/lib/python3.6/site-packages/awx/main/isolated/manager.py", line 432, in run
status, rc = self.check()
File "/var/lib/awx/venv/awx/lib/python3.6/site-packages/awx/main/isolated/manager.py", line 241, in check
self.consume_events(dispatcher)
File "/var/lib/awx/venv/awx/lib/python3.6/site-packages/awx/main/isolated/manager.py", line 294, in consume_events
open(os.path.join(events_path, event), 'r')
IsADirectoryError: [Errno 21] Is a directory: '/tmp/awx_164_pojd2p9l/artifacts/164/job_events/.~tmp~'
2020-03-12 23:43:10,044 DEBUG    awx.main.tasks job 164 (running) finished running, producing 0 events.

# Fixed code
def consume_events(self):
    # discover new events and ingest them
    events_path = self.path_to("artifacts", self.ident, "job_events")

    # it's possible that `events_path` doesn't exist *yet*, because runner
    # hasn't actually written any events yet (if you ran e.g., a sleep 30)
    # only attempt to consume events if any were rsynced back
    if os.path.exists(events_path):
        for event in set(os.listdir(events_path)) - self.handled_events:
            path = os.path.join(events_path, event)
            if os.path.exists(path):
                try:
                    event_data = json.load(open(os.path.join(events_path, event), "r"))
                except json.decoder.JSONDecodeError:
                    # This means the event we got back isn't valid JSON
                    # that can happen if runner is still partially
                    # writing an event file while it's rsyncing
                    # these event writes are _supposed_ to be atomic
                    # but it doesn't look like they actually are in
                    # practice
                    # in this scenario, just ignore this event and try it
                    # again on the next sync
                    continue
                self.event_handler(event_data)
                self.handled_events.add(event)