Skip to content

Waiters #292

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

Open
wants to merge 40 commits into
base: decaf
Choose a base branch
from
Open

Waiters #292

wants to merge 40 commits into from

Conversation

richardwang1124
Copy link

@richardwang1124 richardwang1124 commented Apr 24, 2025

Description of changes:
Support the #waitable trait with waiters. Customers can use code generated waiters through client.wait_until(:waiter_name, params, options).

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

end
expect_any_instance_of(waiter).to receive(:delay).and_wrap_original do |m, *args|
delay = m.call(*args)
expect(delay).to equal(5)
Copy link
Author

Choose a reason for hiding this comment

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

This test case is an example of the question I had in my doc regarding waiter retries. Because the remaining time (5) minus the delay (value between min delay of 3 and max delay of 4) is less than the min delay, the final delay value is set to be equal to the remaining time, which is 5. However, this exceeds the max delay. Is this expected behavior?

Copy link
Contributor

@mullermp mullermp left a comment

Choose a reason for hiding this comment

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

Good start!

}.to raise_error(no_such_waiter_error)
end

it 'does not allow custom waiters' do
Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting. While true, I guess this documents that? I don't think it's needed but you can keep it if you want. I did not add one for paginators.

Copy link
Author

Choose a reason for hiding this comment

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

Depending on whether or not we want to support registering new custom waiters this test case may be modified or removed.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd say just remove it - it's cruft that can break and relies on modifying api private information.

@mullermp mullermp marked this pull request as ready for review May 5, 2025 22:48
Copy link
Contributor

@jterapin jterapin left a comment

Choose a reason for hiding this comment

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

Nice! Great work so far - mini-review since you are working through changes and etc.

Copy link
Contributor

@mullermp mullermp left a comment

Choose a reason for hiding this comment

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

Nice! Getting better. Sorry for the barrage of comments.

@@ -0,0 +1,4 @@
# frozen_string_literal: true

require_relative 'waiters/poller'
Copy link
Contributor

Choose a reason for hiding this comment

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

I would just place these in smithy-client.rb. This file is not big enough to justify loading.

@@ -3,6 +3,44 @@
module Smithy
module Client
module Errors
# Raised when a waiter detects a condition where the waiter can never
# succeed.
class WaiterFailed < StandardError; end
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure where the conversation went, but I think we want these in Smithy::Client::Waiters (but not have an Errors module inside there - just define the errors classes in the waiter namespace in the file where they are raised).

@acceptors.each do |acceptor|
return acceptor['state'] if acceptor_matches?(acceptor['matcher'], output)
end
if output.error.nil?
Copy link
Contributor

Choose a reason for hiding this comment

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

guard clause

equal?(actual, path_matcher['expected'], path_matcher['comparator'])
end

def matches_inputOutput?(path_matcher, output) # rubocop:disable Naming/MethodName
Copy link
Contributor

Choose a reason for hiding this comment

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

For these comments, you can disable once above this method and enable once again after the last method.

end

def matches_success?(path_matcher, output)
if path_matcher == true
Copy link
Contributor

Choose a reason for hiding this comment

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

guard clause


describe 'waiter' do
before(:each) do
shapes['smithy.ruby.tests#GetWidget']['traits']['smithy.waiters#waitable'] = {
Copy link
Contributor

Choose a reason for hiding this comment

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

What I was trying to say in slack is that you can actually define in GetWidget

'traits' => { 'smithy.waiters#waitable' => matchers }

and then in contexts, instead of before(:each) blocks, you can just do

let(:matchers) { .. }

before(:each) do
shapes['smithy.ruby.tests#GetWidget']['traits']['smithy.waiters#waitable'] = {
'SuccessTrueMatcher' => {
'acceptors' => [
Copy link
Contributor

Choose a reason for hiding this comment

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

In general, long, simple line JSONs should be shortened. You can put state, matcher, and success on one line

end
end

context 'flatten' do
Copy link
Contributor

Choose a reason for hiding this comment

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

Is flatten a real matcher? Let's use the terminology from https://smithy.io/2.0/additional-specs/waiters.html

output = {
children: [
{
grandchildren: [
Copy link
Contributor

Choose a reason for hiding this comment

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

Condense please

context 'and inequality' do
before(:each) do
shapes['smithy.ruby.tests#GetWidget']['traits']['smithy.waiters#waitable'] = {
'AndInequalityMatcher' => {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a fundamental difference I think between kotlin's approach and ruby - I don't know if we care to test things like flatten/and inequality, etc - These are really testing JMESPath implementations. I don't think Kotlin has a runtime JMESPath implementation like we do. I think we care to test the basic waiter matcher types (like booleanEquals) and we can rely on the fact that JMESPath handles "&&" expressions without having to test it here. So I think you can cut a good chunk of the tests in this file.

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.

3 participants