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

Convert hello activities to sync #173

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

GSmithApps
Copy link

What was changed

Changed the activities in hello to be synchronous

Why?

To conform to our recommendation of using sync activities unless developers are very sure that their async activities aren't blocking

Checklist

  1. How was this tested:
    ran all the samples and their behavior was unchanged

  2. Any docs updates needed?
    no need

Notes to reviewers

This is a proposal. Please feel free to edit however you see fit. Thank you!

@CLAassistant
Copy link

CLAassistant commented Apr 2, 2025

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@GSmithApps GSmithApps changed the title Convert-activities-to-sync Convert hello activities to sync Apr 2, 2025
Copy link
Member

@cretz cretz left a comment

Choose a reason for hiding this comment

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

Looks great, thanks! We should do this to other samples too, but this is a good start. @dandavison - thoughts?

Thread(
target=self.complete_greeting,
args=(activity.info().task_token, input),
).start()
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this definitely our recommendation or is this a case where it feels more natural for the user to use an asyncio task than to have to explicitly create a thread, seeing as they use asyncio elsewhere with the SDK?

Copy link
Member

Choose a reason for hiding this comment

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

This whole approach is not our recommendation (to just async complete in the background and raise complete). It's meant to demonstrate that it can be done somewhere else. So hacking in a whole new thread like this is probably ok since it's a demonstration of something you would never do anyways, but I would suggest removing the asyncio comments above that are asyncio specific and don't apply to this new code.

Copy link
Author

Choose a reason for hiding this comment

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

I'm okay either way on this! Up to you folks. I went ahead and removed the comments though ✅


# Complete using the handle
await handle.complete(f"{input.greeting}, {input.name}!")
asyncio.run(handle.complete(f"{input.greeting}, {input.name}!"))
Copy link
Contributor

Choose a reason for hiding this comment

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

Using asyncio.run twice in a function in a expositional example surprises me (but I'm new to the sync vs async activity recommendation discussion)

Copy link
Member

@cretz cretz Apr 2, 2025

Choose a reason for hiding this comment

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

Yes, this is actually bad and a bug. This can cause our client to run on two different event loops which is wrong (but may technically work most of the time). To do this right, you should pass the event loop alongside the client in the constructor of this class, and then use run_coroutine_threadsafe on the loop per https://docs.python.org/3/library/asyncio-dev.html#asyncio-multithreading.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks so much for catching this! Should be fixed 👍

@GSmithApps GSmithApps force-pushed the convert-activities-to-sync branch from 4362c80 to eb0f5b7 Compare April 2, 2025 21:06
@GSmithApps
Copy link
Author

Ready if you guys are 🚀

# Let's wait three seconds, heartbeating each second. Note, heartbeating
# during async activity completion is done via the client directly. It
# is often important to heartbeat so the server can know when an
# activity has crashed.
handle = self.client.get_async_activity_handle(task_token=task_token)
for _ in range(0, 3):
print("Waiting one second...")
await handle.heartbeat()
await asyncio.sleep(1)
asyncio.run_coroutine_threadsafe(handle.heartbeat(), self.loop)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
asyncio.run_coroutine_threadsafe(handle.heartbeat(), self.loop)
asyncio.run_coroutine_threadsafe(handle.heartbeat(), self.loop).result()

Here and on the one below so you actually wait on the future. Also we recognize a lack of tests on these hello samples, so can you at least confirm when manually running them they work as expected?

Copy link
Author

@GSmithApps GSmithApps Apr 3, 2025

Choose a reason for hiding this comment

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

Thank you!

(we discussed the run confirmation off-PR)

Copy link
Member

@cretz cretz left a comment

Choose a reason for hiding this comment

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

LGTM, but wait for @dandavison's approval

Comment on lines +54 to +57
# Non-async activities require an executor;
# a thread pool executor is recommended.
# This same thread pool could be passed to multiple workers if desired.
activity_executor=ThreadPoolExecutor(5),
Copy link
Member

Choose a reason for hiding this comment

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

I think all of these samples are going to give warnings of:

Worker max_concurrent_activities is 100 but activity_executor's max_workers is only 5

Can you confirm you are getting these warnings? Can you up the value passed here to 100?

Copy link
Author

@GSmithApps GSmithApps Apr 3, 2025

Choose a reason for hiding this comment

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

I don't think i got those warnings. (Chad and I subsequently discussed off-PR)

Or I can just go ahead and up it to 100 anyway

Copy link
Member

@cretz cretz Apr 3, 2025

Choose a reason for hiding this comment

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

Interesting, I wonder why they aren't showing, we may have to investigate, but lack of warnings appearing is not a blocker for this issue of course

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants