Lightroom SDK: Can't call setPropertyForPlugin from multiple tasks; bug in callWithContext_noyield

  • 3
  • Problem
  • Updated 7 years ago
  • (Edited)
There appears to be no way that two concurrent tasks can call photo:setPropertyForPlugin() without sometimes triggering an error. There's an undocumented workaround that appears to work but doesn't seem kosher.

Here's what happens:

1. Task 1 calls catalog:withPrivateWriteAccessDo().

2. Task 1 calls photo:setPropertyForPlugin().

3. The implementation of setPropertyForPlugin() appears to do a yield().

4. Task 2 tries to call catalog:withPrivateWriteAccessDo() while the same call in task 1 is still active. The following error results:

--------------------
LrCatalog:withPrivateWriteAccessDo: already inside a withPrivateWriteAccessDo() wrapper performing action "(unknown)".
--------------------

Wrapping the call to setPropertyForPlugin() with a call to LrFunctionContext.callWithContext_noyield() should avoid this problem. The documentation says, "calls the function in a fashion that disables LrTasks.yield from working. Use if you need to ensure that the called function is completed as an atomic unit." Unfortunately, it doesn't have any effect.

The same problem occurs if the task calls any number of methods whose implementation calls yield: photo:getRawMetadata(), catalog:createKeyword, etc.

The workaround developed by Rob Cole is to repeatedly try the call to withPrivateWriteAccessDo() until it succeeds, using a back-off algorithm to make the retries more efficient. See this thread:

http://forums.adobe.com/message/29738...

While that appears to get the job done, I don't think that's what was intended by the original design of the SDK. And it's very likely that most plugin authors will never use the workaround, which means that users will be treated to error messages from mysterious race conditions.

For a sample plugin that demonstrates the problem, see:

http://www.johnrellis.com/lightroom/p...
Photo of John R. Ellis

John R. Ellis, Champion

  • 3694 Posts
  • 966 Reply Likes

Posted 7 years ago

  • 3
Photo of Rob Cole

Rob Cole

  • 4831 Posts
  • 382 Reply Likes
Photo of John R. Ellis

John R. Ellis, Champion

  • 3694 Posts
  • 966 Reply Likes
Thanks, I found one of your posts but missed that one.
Photo of Rob Cole

Rob Cole

  • 4831 Posts
  • 382 Reply Likes
It'll be interesting to see what Adobe comes up with to "fix" this "bug".
Happy New Year,
Rob
Photo of John R. Ellis

John R. Ellis, Champion

  • 3694 Posts
  • 966 Reply Likes
If callWithContext_noyield() worked as documented, then plugins would just need to wrap the body of withPrivateAccessDo() with callWithContext_noyield().

But I suspect there might be a deeper flaw in the architecture of the task scheduler and/or catalog-access methods that could be very hard to address. But just a guess...
Photo of Rob Cole

Rob Cole

  • 4831 Posts
  • 382 Reply Likes
I checked that callWithContext_noyield() will throw an error if you try to call LrTasks.yield. But it seems that if withPrivateAccessDo() does yield somehow, then catching it as an error still won't help. i.e. it needs to not yield, rather than throw an error when it does. As you've suggested, that alone may not be a proper solution either... - this story still unfolding... Cheers, Rob.
Photo of John R. Ellis

John R. Ellis, Champion

  • 3694 Posts
  • 966 Reply Likes
It appears that LR 4 beta has addressed this issue by adding a timeout parameter to LrCatalog:withPrivateWriteAccessDo, based on this new error message:



I wasn't able to reverse engineer the new function signature, though -- presumably it will be documented in the final-release SDK documentation.
Photo of Rob Cole

Rob Cole

  • 4831 Posts
  • 382 Reply Likes
Awesome - you *and* Adobe :-)