4 ms·
The signature for a controller to implement is as follows: Controller *interface* boot[*itemIs* Item, *signedIs* Signed] → TerminationReport
by ProfHewitt 7y ago
The signature for a controller to implement is as follows:
Controller *interface*
boot[*itemIs* Item, *signedIs* Signed] → TerminationReport
// boot request with an item and signed returns
// a termination report from the boot request
shutDown → Void // shut down request returns Void
The challenge in Erlang is to allow the shutDown request to be received even though the boot request has not yet returned with a termination report.
The cancellation exception is caught within the implementation of the run request and turned into a termination report.
PS. The definition the type Item is as follows:
Item ≡ Package[*imageIs* Binary, *versionIs* Version]
- toast0 7y agoOh, I think I see. How about fun Self (State) -> {PublicKey, Ref, Function} = case State of {P, R, F} when is_ref(R), is_function(F) -> {P, R, F}; Other -> {Other, false, false} end, CurrentVersion = 1, receive {upgrade, Function, NewVersion, Signature} when Ref == false -> SignRef = make_ref(), async_sign_checker({self(), SignRef}, PublicKey, Function, NewVersion, Signature), Self({PublicKey, SignRef, Function, NewVersion); {upgrade, _, _, _} -> throw (no_concurrent_upgrades); {sign_check, SignRef, true} when Version > CurrentVersion -> Function(PublicKey); {sign_check, SignRef, true} -> throw(bad_version); {sign_check, SignRef, false} -> throw(bad_signature); {sign_check, _, _} -> throw(bad_sign_check); shutdown -> ok; _Other -> % here's where you handle work % But I don't know what work you wanted to do, % so I'm just looping Self(PublicKey) end end. assuming async_sign_check sends back something sensible {sign_check, SignRef, true}. async_sign_check would send the work to another process, if you want it to stop checking the signature in case of early shutdown, the processes could be linked. Although, I'm still not quite sure I understand the system you're trying to get to. This in the context of {become, F}, so I'm assuming you want the process receiving the boot request to become the requested function. But you also want a termination report; and I'm assuming the function isn't expected to terminate, it's expected to receive and process requests. But, you didn't tell us where you want these reports sent? In my updated code, there is certainly a possible window where the signature checker finished near the same time as a shutdown request was sent. In that case, if the shutdown request is received first, the process would shutdown; if the signature result is received first, that would be processed, and if the signature result and versioning was good, the process would become the new function, and that function would receive the shutdown request. If the new function has some complicated setup, and you wanted to shut it down in the middle of that, you would most likely need to use erlang:exit(Pid, kill); although, a carefully written function could periodically check for a shutdown message in the middle of startup. I don't find that a terribly useful usecase --- if you started something, let it finish starting, or just brutally kill it; architecting a clean shutdown from a partial start is most likely to be wasted effort, instead, one should architect their start so it doesn't perturb the state of the world until it is fully started and can be expected to shutdown cleanly.
- ProfHewitt 7y agoLooks like you are still not implementing the signature of a Controller, which as follows: Controller *interface* boot[*itemIs* Item, *signedIs* Signed] → TerminationReport // boot request with an item and signed returns // a termination report from the boot request shutDown → Void // shut down request returns Void A boot request checks the item which is a Package with code and packageVersion and then runs the code. The boot request returns a termination report that results from running the code. However, when the boot request is still operating, the controller might receive a shutDown request, which will cause the cancellation of the running code that will caught within the run request and turned into a termination report. Note that there is no timing error in the Actor implementation because, a shutDown request cannot be received until code.run has released the region of mutual exclusion.
- deleted 7y ago[deleted]
- toast0 7y agoOK, so this isn't really {become, F}, this is {run, F}. The function F, is expected to return results and terminates, so it is no longer running (but, it could have spawned a process or otherwise changed the world state; Erlang is generous with respect to side effects) I don't really understand the version number means in this case? You can only run functions with the same or greater versions than had previously been run? I think you're somehow asking for this to be both synchronous, in the sense that the result of running the function is returned directly and asynchronous in that you'd like to be able to cancel it. If you want the return directly, I can't also have previously returned a cancellation id. If you just want to run a function, and get the results back, that's not that hard; but before I write the code for that, I want to really be sure what you're asking for.
- ProfHewitt 7y agoWith respect to your question: "I don't really understand the version number means in this case?" An item can be booted only if its version number has not regressed in to prevent replay attacks. There are no cancellation ids in the Actor implementation, however a cancellation exception can be thrown when an activity is cancelled.