-
Notifications
You must be signed in to change notification settings - Fork 48
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
Add a simple context plugin #43
Conversation
what do you think? |
Now that I think about this, because the cost of just having context always I originally thought a plugin was a good path because I was worried the implementation much touch or alter the core code paths for a feature a lot of people might not use. I thought this could potentially make the core code paths more complicated. I didn't like that potential trade off. This approach just adds an optional hash allocation to config, and What do you think? |
i was going to post some suggestion more or less exactly like that but i was hoping you'd come to that conclusion yourself. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor comments
@@ -1,5 +1,7 @@ | |||
## HEAD | |||
|
|||
* Added contexts feature. Thanks to @apurvis. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're missing a version number here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh what I usually do is put new feature/bug fixes in HEAD, and then when I cut a new version, I'll move the new stuff into that version. Since sometimes I collect a few features or bug fixes before doing a version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whatever you prefer; i'm just used to always having the next version being the first line of the changelog
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't always know if the next version will be major, minor, or patch until I know everything going into it. So I keep it HEAD until I cut the version.
lib/retriable.rb
Outdated
yield(config) | ||
end | ||
|
||
def config | ||
@config ||= Config.new | ||
end | ||
|
||
def retriable_with_context(context_key, options = {}, &block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could even just name the method with_context
? then you have Retriable.with_context
... reads pretty well, actually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I named it with_context
initially, but the problem is I didn't like that if you use the kernel extension that you couldn't really put with_context
on the Kernel since it's too generic. I didn't like the idea of having it be #retriable
map to Retriable.retriable
but #retriable_with_context
in Kernel map to Retriable.with_context
.
I agree retriable_with_context
is kind of verbose, I'm still thinking about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't like the idea of having it be
#retriable
map toRetriable.retriable
but#retriable_with_context
in Kernel map toRetriable.with_context
.
i tend to view adding methods to Kernel
as kind of way more intrusive than, for instance, implementing method_missing
within the gem... i would probably vote to deprecate it altogether if i had my druthers (which i don't; just putting that out there)
point being, i think Retriable.with_context
reads really well, and if the kernel extension can't match the semantics, it doesn't really bother me (though i agree it's not quite as neat & tidy)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
retriable
is honestly a pretty generic thing to be injecting into Kernel
- no more or less generic, at least, than with_context
IMHO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I had to write it again I might leave out the kernel extension, but I don't want to break it for people upgrading. I changed it to name it with_context
unless you use the kernel extension, then it's retriable_with_context
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah you'd have to deprecate it and then wait until the next major version... even then it might not be worth breaking people's shit.
if you were considering that approach though, you could deprecate it now.
lib/retriable/config.rb
Outdated
@@ -9,6 +9,7 @@ class Config | |||
:timeout, | |||
:on, | |||
:on_retry, | |||
:context, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
plural contexts
, since there are multiple?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'll change that.
lib/retriable.rb
Outdated
|
||
retriable(config.context[context_key].merge(options), &block) if block | ||
end | ||
|
||
def retriable(opts = {}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you're going to declare the &block in the with_retriable
args, might as well add it here too. might help generations to come read the code slightly.
There was a problem hiding this comment.
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 need the block here because we call yield here. retriable_with_context
needs it because I need to pass the block into #retriable
without calling it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah you don't need it, but it does make it clear that the method takes a block - just makes the method signature fully explicit because otherwise the yield
is kinda buried way in there (where it needs to be, but it's a little hard to spot at first). up to you really, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good to me; you know my thoughts on the final naming decision but overall 👍
so stoked this feature will finally get in there - glad you ultimately realized it's not that big a change - but i think it will see a ton of usage. your dominance over Retryable is assured |
…nel extension to keep it descriptive
Already have more stars, so that's a good sign ;D |
pretty unrelated, but i've been using "squash+merge" more than just plain old merge to keep the commit history of my projects a bit cleaner. YMMV |
I use squash merge as well. |
lib/retriable.rb
Outdated
yield(config) | ||
end | ||
|
||
def config | ||
@config ||= Config.new | ||
end | ||
|
||
def with_context(context_key, options = {}, &block) | ||
if !config.contexts.key?(context_key) | ||
raise ArgumentError, "#{context_key} not found in Retriable.config.contexts" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could maybe make this exception more useful by listing #{Retriable.config.keys}
/shrug
…t key that doesn't exist
yield(config) | ||
end | ||
|
||
def config | ||
@config ||= Config.new | ||
end | ||
|
||
def with_context(context_key, options = {}, &block) | ||
if !config.contexts.key?(context_key) | ||
raise ArgumentError, "#{context_key} not found in Retriable.config.contexts. Here the available contexts: #{config.contexts.keys}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Here are the...." ;)
or just say "Available contexts: "
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Damn, I'm getting sleepy and wanted to cut a new version. I'll bundle the typo fix in with the next patch version!
This was inspired by this PR by @apurvis: #39
In reviewing that PR there were a few design decisions that I wasn't a fan of, but in reviewing it I didn't have an immediate suggestion or alternative. The issues for me where:
Hash
. Core classes are usually heavily or partially written in C for speed and can behave in unexpected ways. I prefer composition or delegation when that can be utilized, in this approach, I just madecontext
a simple hash composed on theRetiable
module.method_missing
onRetriable
just to support context, using a simple Hash made it pretty easy to call using the key in awith_context
method.config
with contexts, this approach separates config from context without context support having to touch theconfig
object at all.I spiked on experimenting with a simpler implementation and came to this. Using that PR's example:
Config:
Usage: