Closed t089 closed 1 year ago
I wonder if the userInfo
dictionary of JSONDecoder
is thread-safe. What happens when the prepareDecoder
method is called concurrently for a shared client?
Hm this looks suspicious: The JSONDecoder
seems to be shared with all requests handled by the client, which is fine, but the problem might be that the userInfo
dict is being mutated in RequestHandlerType.dispatch<T: Decodable>(request: KubernetesRequest, expect responseType: T.Type) async throws -> T
when it calls perpareDecoder(jsonDecoder)
.
@t089 Thanks for the bug report 👍
It seem, like you're onto something. The thread-safety of the userInfo
is very likely to be the culprit here. I guess, it won't be easy to reproduce 🤔
I'll try to find a solution for propagating the userInfo
in an async context.
One fix for this would be the no-code approach 😉. The userInfo
dictionary is only required for decoding an unknown type to a type-erased AnyKubernetesAPIResource
.
I was planning on dropping the AnyKubernetesAPIResource
because it was superseded by the UnstructuredResource
in SwiftkubeModel v0.5.0. Its usage is demonstrated in the swiftkube-c-t-l
example here
However, there are some missing bits and pieces, in order to completely make the transition.
other quick fixes:
unserInfo
with a global lock (should be mostly fine unless there are a TON of concurrent requests within the same process).Yes, however, there are some drawbacks with keeping that code, since it was more-or-less a workaround for decoding unknown types. With the introduction of GroupVersionResouce
, UnstructuredResource
and derivatives in v0.5.0, there is no need anymore for this workaround.
Besides, I think it is better to avoid creating a decoder for each request, in order to be more memory friendly. And a global lock would be another workaround.
Yes, sounds reasonable!
Hello, not sure if this helps, but I noticed a crash in an app today that might be related to SwiftkubeClient. This is the backtrace:
At this time the app was most likely doing only one thing: watching a list of Pods.
And
refreshTargets
only does this withclient
: