Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/status event scheduler #1193

Merged
merged 8 commits into from Nov 2, 2017
Merged

Conversation

LearnedVector
Copy link
Contributor

This PR gives an api for skill developers to query event status from the event scheduler

(_datetime, time_left) = self.get_event_status(name_of_scheduled_event)

#_datetime is the datetime object that the event will go off
# time_left is the seconds left in epoch time till the event go off

====  Tech Notes ====
This allows you to remove message bus messages inside core.py. When canceling scheduling events, the message bus messages were not removed which could caused duplicate listeners and handlers for the same intent. Adding remove_event function removes the actual messages from the bus to prevent potential duplicates.
Copy link
Collaborator

@forslund forslund left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very slick in general. I'd like a timeout if there is some problem along the way.


# this is needed because message.data could return None
# and that would make the while loop infinite
self.event_status = "None"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would personally have used the None type as a default value

self.emitter.once(emitter_name, callback)
self.emitter.emit(Message('mycroft.scheduler.get_event', data=data))

while True:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably have a timeout of say two seconds, and do sleeps between checks to avoid hogging the cpu:

start_wait = time.time()
while event_status is None and time.time() - start_wait < 2.0:
    time.sleep(0.1)
return event_status

(Having it return None on failure is a common approach in python)

Copy link
Collaborator

@forslund forslund Nov 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be even better if it raised an exception on timeout. Not sure which one would be approprate. IOError or some from the websocket client?

Not critical, you decide which way you like best.

@LearnedVector
Copy link
Contributor Author

@forslund did some changes. Also i realized this PR also contains the remove_event code from the other PR. Should we just close the other PR and have this one for both?

@MycroftAI MycroftAI deleted a comment Nov 1, 2017
@MycroftAI MycroftAI deleted a comment Nov 1, 2017
@MycroftAI MycroftAI deleted a comment Nov 1, 2017
@forslund
Copy link
Collaborator

forslund commented Nov 1, 2017

Yes, might be better to close that.

@forslund forslund added the CLA: Yes Contributor License Agreement exists (see https://github.com/MycroftAI/contributors) label Nov 2, 2017
Copy link
Collaborator

@forslund forslund left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I Ran into an issue when trying to get status for non-existing events. It indicated it got a timeout but actually there was a silent exception in the callback when trying to access the message data.

event_status = [None]

def callback(message, event_status):
event_time = int(message.data[0][0])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs check if message.data is not None since that is a valid response if event doesn't exist. If it is None set event_status[0] to False or 0 to indicate that it doesn't exist.

(Timeout exception is a bit misleading if the actual issue is that the handler doesn't exist)

# making event_status an object so it's refrence can be changed
event_status = [None]

def callback(message, event_status):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

event_status don't seem to be needed as an argument

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is actually needed to be able to change the value of the event_status. If this is not passed this way to the callback then when we say event_status = whatever, it won't reference the same variable.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, when I tested it wasn't needed. As long the outer_var is a mutable (in this case a list) it should work.

def outer():
    outer_var = [None]
    def inner():
        outer_var[0] = 'Modified'

    inner()
    print outer_var[0]

outer()

I'll retest but it's not really important, this way works as well.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok retried and it doesn't seem necessary but never mind both ways work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh ok thanks!

@LearnedVector
Copy link
Contributor Author

@forslund made some changes and also changed the function name for scheduled events to be more expressive of what it's doing. let me know what you thiink

while event_status[0] is None and time.time() - start_wait < 3.0:
time.sleep(0.1)
if event_status[0] is False:
raise Exception("Scheduled Event not found for {}".format(name))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if I was unclear (or confused, or both) earlier. I meant that the function should return None if there is no scheduled event.

A use case I can imagine is to check if an event is scheduled at all and checking if The self.get_scheduled_event_status(event) is None is a pretty simple way to do it.

Timeout is an actual error while "event isn't scheduled" is a valid status (at least in my mind).

What's your opinion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes a lot of sense to me!

@LearnedVector
Copy link
Contributor Author

@forslund let's try this again!

@forslund
Copy link
Collaborator

forslund commented Nov 2, 2017

Awesome, looks and works great! Merging

@forslund forslund merged commit 572f591 into dev Nov 2, 2017
@penrods penrods deleted the feature/status_event_scheduler branch November 9, 2017 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA: Yes Contributor License Agreement exists (see https://github.com/MycroftAI/contributors)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants