-
Notifications
You must be signed in to change notification settings - Fork 9
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
ActionPolicy does not work well with graphql-ruby dataloaders (not thread/fiber safe) #47
Comments
Thanks for the report! Just to confirm that it relates to the ActionPolicy::PerThreadCache.enabled = false (Though, I think, |
@palkan We have, through monkey patching disabled According to us the sequence of events is something like this:
|
Thanks for the details! That will help with reproduction in tests. Also, I think it's worth extracting the minimal behaviour implementation into a separate module, so it's possible to opt-out from extensions (such as memoization) without monkey-patching. |
Hi @palkan I was wondering if you had any idea on how to proceed with this. I saw you started a branch some time ago, but it hasn't moved much (publicly) since then. I was looking into the code, and from where I'm sitting, it looks like some major overhaul of the internal implementation is required. I'd love to help where I could , but as it looks like a big change, some guidance on how you'd like to do this would be needed. |
@Bertg Could you add some context, please. class RenewalPolicy < BasePolicy
authorize :dataloader, optional: true
def update?
scopes = dataloader.with(Sources::ScopesForUser).load(user.id)
global_scopes = scopes.include?("...")
# CODE
end
end |
We have only discovered it in The issue here is how To be clear: In the following bot of code, from # Returns a result of applying the specified rule (true of false).
# Unlike simply calling a predicate rule (`policy.manage?`),
# `apply` also calls pre-checks.
def apply(rule)
@result = self.class.result_class.new(self.class, rule)
catch :policy_fulfilled do
result.load __apply__(resolve_rule(rule))
end
result.value
end I mentioned before, that this is exactly what happens during the response generation phase in So, in short |
@Bertg Thanks a lot for the details. Sorry, hadn't had enough time to proceed with this issue: still don't have a reproduction setup :(
That's true. I plan to start working on v1.0 release soon, and this particular refactoring is on my list. |
Hi folks, hate to dig up an old thread here. I came across this while starting to switch from pundit to Action Policy and need to know the latest. We use GraphQL and Dataloaders, and so I'm wondering what the current state of this is. In particular: since we use dataloaders, should we avoid using Action Policy at all? Are the issues with Action Policy itself (my understanding of the above) or only with the GraphQL integration (since this is an issue on the GraphQL gem)? Is there a way to configure Action Policy to work around the issues above -- does disabling the thread cache do enough? If so, what are the tradeoffs? Is there any ongoing or partial, past work on this subject? What's left? Is there something we could do to help move along better support? |
Store the result object in the execution context instead of the ivar to avoid problems in fiber-concurrent execution environments This is a temporary workaroudn with some preparation for 1.0; ideally, we should get rid of the local-global state completely Ref palkan/action_policy-graphql#47
Store the result object in the execution context instead of the ivar to avoid problems in fiber-concurrent execution environments This is a temporary workaroudn with some preparation for 1.0; ideally, we should get rid of the local-global state completely Ref palkan/action_policy-graphql#47
Pushing me in the right moment is enough 😁 Looks like I finally got my mind around it. The biggest blocker was the lack of a reproduction script. So, I wrote a synthetic one just to demonstrate (and fix) the problem: palkan/action_policy@29af4bc#diff-4ddbfab2d660b8eec0da3c00e45d1daaa23a08c83c914086ef3b148459d2ce43 The fix is available in |
Tell us about your environment
Ruby Version: ruby 3.2.2
Framework Version (Rails, whatever): rails (7.0.4.3), graphql (2.0.21)
Action Policy Version: (0.6.5)
Action Policy GraphQL Version: (0.5.3)
What did you do?
We started using dataloader in our policies to help reduce the amount of queries.
We pass the graphql context as part of the policy context, which allows us to use our dataloaders in the database.
What did you expect to happen?
We expected everything to keep working as it did, but with less or equal amount of queries.
What actually happened?
We started getting completely wrong results when using
expose_authorization_rules
.During our investigation we monkey patched the
allowance_to
method like this:We got following (sample) output.
As you can see a discrepancy on the
rule
is exposed. The result that is returned is not that of the rule requested.In order to understand what is happening it is important to know that resolving of these policies have (somewhere in the stack) a call to dataloader. Dataloader uses fibers to do its "magic", basically stopping execution of functions as long as it can.
This seems to be incompatible with the (default on)
ActionPolicy::Behaviours::Memoized
andActionPolicy::Behaviours::ThreadMemoized
. When calling theapply
method (in allowance_to) the result is stored in the instance. When the thread is yielded (by the fiber scheduler) other threads can replace this result with an other call to apply.As I see it this implementation can not be considered thread safe, especially in its default configuration.
The text was updated successfully, but these errors were encountered: