Comments (8)
Hi, I'm pleased to find this issue here; I was just searching around for a gem that could help with an idea I had about exceptions in ruby, defensive programming, and degrading functionality while still completing the request.
I've been reading Armstrong 2003 and while getting excited about Erlang I feel frequently in my work that we don't have adequate patterns to express multi-step processes and write code that tolerates failure from other components or apps. I enjoy using light service to encapsulate steps and shrink classes, but when there's an exception, it just drops out, or if you fail_with_rollback! you can run the rollback block.
I need to think more about this to decide what sort of API to propose, but off the top of my head I'm considering either providing an array of ordered fallbacks to the reduce method, or writing the fallbacks into the action itself.
class CalculatesTax
include LightService::Organizer
def self.for_order(order)
with(:order => order).reduce(
[FetchesTaxRangesAction, FetchesCachedTaxRangesAction],
LooksUpTaxPercentageAction,
CalculatesOrderTaxAction,
ProvidesFreeShippingAction
fallback: GenericErrorHandler
)
end
end
I think the former is preferable, if you can provide a generic failure action as an additional parameter. That way you avoid coupling generic error handling code to specific, small actions and avoid inflating those classes. Perhaps there's a little of value in both...
from light-service.
For writing fallbacks into the action itself, can't you do the following (when a failure happens within an action)?:
class FetchesTaxRangesAction
include LightService::Action
executed do |ctx|
begin
// fetch tax ranges here
rescue TaxApi::ApiLicenseInvalid => e
// use alternative api license
rescue => e # any other error
// fetch cached tax ranges
ensure
// does something regardless if this succeeds or not
end
end
end
This is what first popped in my head when I read your suggestions @carlthuringer:
class FetchesTaxRangesAction
include LightService::Action
executed do |ctx|
// fetch tax ranges here
end
fallback do |ctx|
// fetch cached tax ranges
end
end
Although I'm not exactly sure how it will be helpful (or if I understood the problem of this issue at all). Already in the wee hours so pardon me if this doesn't make sense.
from light-service.
I want to minimize the use of control structures to handle errors, and instead provide alternatives actions to the Organizer. It's important that each Action is completely unaware of the alternatives. Lower coupling, ease of modification, and improved readability, which are all key goals of light-service, as I understand it.
Sometimes it may be necessary to know exactly what the error was, and correct it specifically, as you demonstrated with the alternate api license. In those cases I think that the argument tips in favor of plain ruby begin...rescue
blocks.
Given a little bit more time I hope I can come up with a more compelling case where this makes sense as an alternative to just specifying one or more fallbacks as blocks with a fallback
macro. It may be that each pattern has benefits (decoupling vs context/responsibility of action).
The point behind supplying alternative actions is to avoid coding error-handling logic inside of the actions, and instead build a framework that automatically attempts something more achievable when the optimum solution fails. Each successive alternative in the array of actions should be easier to achieve than the previous, and somewhat degraded.
I admit that I don't have a complete plan/philosophy of where the responsibility for handling errors lies, but I find that the removal of the nil check is very compelling. Unfortunately my example is contrived, and many, many things could be done instead to avoid the need for a nil check, so I hope this won't distract from the proposal.
from light-service.
@carlthuringer
This is a bit late but couldn't you do something like
class CalculatesTax
include LightService::Organizer
def self.for_order(order)
with(:order => order).reduce(
[FetchesTaxRangesAction, FetchesCachedTaxRangesAction],
LooksUpTaxPercentageAction,
CalculatesOrderTaxAction,
ProvidesFreeShippingAction
)
rescue
GenericErrorHandler.execute
end
end
?
from light-service.
We needed to signal the warning in the context
, back to the controller. It means the Organizer processed, records were saved, but something happened the user should be aware of.
from light-service.
I think we need a larger, more concentrated effort around error handling/warning. Can I close this issue or is there anything else to discuss?
from light-service.
I don't see much activity around this issue. Can I close it? I don't think I have the need for it right now.
from light-service.
Well, I already asked this question 5 months ago, closing it now.
from light-service.
Related Issues (20)
- Is there a LightService-like project in Python? HOT 2
- Yard Documentation to code write with light-service HOT 4
- Deprecation warning using organizer within an organizer HOT 7
- Rollback Block Not Invoked In Iterated Actions HOT 10
- Testing actions in isolation HOT 4
- [RFC] Closing pull requests while a new build is starting causes failures HOT 1
- Running actions in jobs HOT 11
- reusing modules within actions
- Surprising `add_to_context` orchestrator behaviour HOT 1
- How to handle default values for dependency injection? HOT 9
- Help testing LS release candidate HOT 6
- Why this gem add activesupport as runtime dependency? HOT 11
- around for Actions HOT 3
- Namespacing Organizers and Actions HOT 1
- Confused about context failure HOT 1
- Can I chain Organizers together? HOT 5
- `reduce_case` not supported when running Ruby < 2.7, but not documented as such HOT 1
- README's built-in localization adapter documentation has a bug
- How about an "after" hook that will be called after "fail_and_return!"? HOT 2
- Remove the ActiveSupport dependency
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from light-service.