Cross posted on community.wolfram.com (new comments)
TLDR
There is a pool of kernels/sessions available for each user, you don't have control over the pool only over specific kernel you currently evaluate in. Re-upload of a package should be followed by Quit[]
in every kernel where previous version of a package was used. I failed to find tools for that.
Moreover, you can Quit[]
via browser notebook interface but can't via CloudEvaluate
or APIFunction
so there is no way to clear specific kernel used by APIFunction.
Background
I am developing a package which I want to deploy to my Wolfram Public Cloud's account and I want a set of APIFunctions
/FormFunctions
/etc to be able to use it.
PacletManager
has limited functionality, so I am just uploading the package archive and extract it to WPC's$UserBaseDirectory / Applications /
.APIFunctions
and friends have the form:APIFunction[{}, (Needs["TestPackage`"];Symbol["TestPackage`api2"][...]) &]
I use
Symbol
because otherwiseTestPackage`
definitions are uploaded and I want to avoid that. There should be one code source, the package in$UserBaseDirectory
.
Problem
The problem is that kernel management on WPC is a closed black box. If you call the API twice, each time it uses one of the kernels from the pool. This also applies to CloudEvaluate
etc.
$UserBaseDirectory
is shared, but Get
will find the current version only for the current kernel.
If in another kernel TestPackage`
was loaded earlier, Needs
will not load the current version there :-/ I do not want to use Get
in my APIFunctions, the proper way is to call Needs
.
And there is no way to Quit
each available kernel.
Example
is worth 10^3 words:
First we will mimic a package upload, 10 times. So it was uploaded, something was fixed, it was uploaded again, etc:
packageTemplate = StringTemplate["
BeginPackage[\"TestPackage<*\"`\"*>\"];
myValue = \"``\"
EndPackage[];
"];
Do[
CloudExport[packageTemplate@RandomReal[], "Text", "TestPackage.m"]
; CloudEvaluate[
CopyFile[
"TestPackage.m"
, StringRiffle[
{$UserBaseDirectory, "Applications", "TestPackage.m"}
, "/"
]
, OverwriteTarget -> True
]
; Get @ "TestPackage`"
]
, {10}
]
Now let's call the code based on the package 25 times:
Table[
CloudEvaluate[
Needs["TestPackage`"]
; {$SessionID, Symbol["TestPackage`myValue"]}
]
, {25}
] // CountBy[Last] // Normal // Column
7 different results, I expect 1, the value from the 10th deployment!
The question
How to upload a package properly, as we can see Get
after the upload only affects one particular kernel. CloudEvaluate@Quit[]
will not help either.
How to reset them all?
Requirements
APIFunction[{}, (Get["TestPackage`"];Symbol["TestPackage`api2"][...]) &]
could solve it but if the package contains Protected
/Locked
symbols you will get a flood of errors. And because of the same reason you can't ClearAll
symbols. And obviously you can't Quit
in APIFunction
.
Further reading
The problem was known but not diagnosed already 3 years ago:
Internal`Restart[]
would help? $\endgroup$