package async_rpc_kernel
- Overview
- No Docs
You can search for identifiers within the package.
in-package search v0.2.0
Install
dune-project
Dependency
Authors
Maintainers
Sources
sha256=68faba3ee99cd14836e313a2a24557ed588d2042000b3472be632bc861bd39f7
md5=f435ab9bfb29aa43be1e0aa6b295252b
doc/CHANGES.html
v0.10
- Exposed function
Rpc.dispatch', which is likedispatchbut returns anRpc_result.t, which has more information than theOr_error.treturned bydispatch.
113.43.00
- Add some benchmarks for Pipe_rpc
Optimize the server side of Pipe RPC and add an expert interface. This feature will benefit all Pipe RPC implementors.
At base:
┌─────────────────────────┬──────────┬─────────┬────────────┐ │ Name │ Time/Run │ mWd/Run │ Percentage │ ├─────────────────────────┼──────────┼─────────┼────────────┤ │
bench.mldirect write │ 148.87ns │ 126.00w │ 100.00% │ └─────────────────────────┴──────────┴─────────┴────────────┘At tip:
┌────────────────────────────────┬──────────┬─────────┬────────────┐ │ Name │ Time/Run │ mWd/Run │ Percentage │ ├────────────────────────────────┼──────────┼─────────┼────────────┤ │
bench.mldirect write │ 69.71ns │ 3.00w │ 94.99% │ │bench.mldirect write expert │ 73.39ns │ │ 100.00% │ └────────────────────────────────┴──────────┴─────────┴────────────┘Note: the reason the expert version is slightly slower is identified: if we replace the
blits byunsafe_blits inrpc_transport_low_latency.ml, then the expert version becomes faster.The RPC tests for Pipe RPC showed a nice improvement on the server side: lower CPU consumption and roughly 20% faster
Remove the ~update argument from State_rpc.dispatch.
Before this feature, the dispatch method for State_rpcs looked like this:
val dispatch : ('query, 'state, 'update, 'error) t -> Connection.t -> 'query -> update : ('state -> 'update -> 'state) -> ( 'state * ('state * 'update) Pipe.Reader.t * Metadata.t , 'error ) Result.t Or_error.t Deferred.t
There are a couple of cases where having the
updatemethod there can be cumbersome:- sometimes the type of the state that it sent over the wire is different from the type that is naturally maintained on the client side.
- sometimes the update method needs to perform some Async computation to return a new state.
It feels like the method is trying to be helpful, but has more of a tendency of getting in the way. This feature removes this method.
The old API may be reinstated by using a
Pipe.fold_mapas below:State_rpc.dispatch rpc connection query
- Add support for
State_rpcsinVersioned_rpc.Callee_converts. Implementation and interface very closely resemble that of a Pipe_rpc.
113.33.00
Cleans up the implementation-side interface for aborting
Pipe_rpcs.Summary
The
abortedDeferred.tthat got passed toPipe_rpcimplementations is gone. The situations where it would have been determined now close the reading end of the user-supplied pipe instead.Details
Previously, when an RPC dispatcher decided to abort a query, the RPC implementation would get its
abortedDeferred.tfilled in, but would remain free to write some final elements to the pipe.This is a little bit more flexible than the new interface, but it's also problematic in that the implementer could easily just not pay attention to
aborted. (They're not obligated to pay attention to when the pipe is closed, either, but at least they can't keep writing to it.) We don't think the extra flexibility was used at all.In the future, we may also simplify the client side to remove the
abortfunction on the dispatch side (at least when not usingdispatch_iter). For the time being it remains, but closing the received pipe is the preferred way of aborting the query.There are a couple of known ways this might have changed behavior from before. Both of these appear not to cause problems in the jane repo.
- In the past, an implementation could write to a pipe as long as the client didn't disconnect, even if it closed its pipe. Now writes will raise after a client closes its pipe (or calls
abort), since the implementor's pipe will also be closed in this case. Doing this was already unsafe, though, since the pipe was closed if the RPC connection was closed. abortedwas only determined if a client aborted the query or the connection was closed. The new alternative,Pipe.closedcalled on the returned pipe, will also be determined if the implementation closes the pipe itself. This is unlikely to cause serious issues but could potentially cause some confusing logging.
- In the past, an implementation could write to a pipe as long as the client didn't disconnect, even if it closed its pipe. Now writes will raise after a client closes its pipe (or calls
Blocking RPC implementations (i.e., ones made with
Rpc.implement') now capture the backtrace when they raise. This is consistent with what happens in the deferred implementation case, since in that case the implementation is run inside aMonitor.try_with, which captures backtraces as well.Here's an example of what a new error looks like:
((rpc_error (Uncaught_exn ((location "server-side blocking rpc computation") (exn (Invalid_argument "Float.iround_up_exn: argument (100000000000000000000.000000) is too large")) (backtrace "Raised at file "pervasives.ml", line 31, characters 25-45 \nCalled from file "result.ml", line 43, characters 17-22 \nCalled from file "monad.ml", line 17, characters 20-28 \n")))) (connection_description ("Client connected via TCP" (localhost 3333))) (rpc_tag foo) (rpc_version 1))
- Actually deprecated
deprecated_dispatch_multifunctions inVersioned_rpc.
113.24.00
- When
Transfer.Writer.send*raises, send an error to the client. - Added
Pipe_rpcinVersioned_rpc.Both_convert. - Switched to ppx.
- Expose the lower-level registration hook in
Versioned_rpc. - Allow custom handling of missed async_rpc heartbeats.
Client-side State_rpc
dispatchfunction does not behave well when the reader side of the pipe is closed.It should gracefully abort the rpc instead of raising exceptions, or whatever it currently does.
Add
Rpc.Expert.implementandRpc.Expert.implement'with a similar interface asOne_way.Expert.implementbut for 2-way rpcs.Exceptions raised by an expert implementations are handled as follow:
- if the query has already been answered, stop the server (as for one-way expert)
- if not, send a
Rpc_error.Uncaught_exn(as for 2-way rpc)
Adds
Rpc.Pipe_rpc.dispatch_iter, plus a bunch of additional types to support it. The main reason for this is to reduce space usage:Pipe_rpc.dispatchfollowed byPipe.iter_without_pushbackconsumes ~105 words in the steady state (i.e., when no messages are coming in) whiledispatch_iterconsumes ~15. I'm suredispatchcan be improved a lot, but a pipe by itself is 46 words, so it can't possibly become as small asdispatch_iter.Both cases can be made smaller by making
Connection.response_handlera GADT instead of a closure. I plan to do this later.One annoying property of the interface is that the only way to cancel a subscription is to use
Pipe_rpc.abort, which has a terrible interface. The logical way to improve the interface is to return a record of aPipe_rpc.t, aConnection.t, and aQuery_id.t, which allocates an additional few words. I'd kind of like to do this but it seems counter to the goal of reducing space usage.Adds
Rpc.Pipe_rpc.implement_direct, which uses a "direct stream writer" to write results to the other side, rather than using aPipe.Writer.t. This consumes much less memory, ~15 words per open query as opposed to ~225 for a regularPipe_rpcimplementation.A large part of the diff in this feature is the addition of a module
Implementation_types, which just contains copies of type definitions fromImplementationandImplementations. This is necessary to handle some cyclic type definitions (both of these modules now depend on types defined in the other module).This is the implementation-side dual of
Pipe_rpc.dispatch_iter.Change
Command_rpc.Commandto useVersioned_rpc.Callee_convertsinstead ofVersioned_rpc.Both_convertso that commands can be constructed without client-side conversions. Clients remain free to use conversions or not, as appropriate.Removed
val rpcsfromCallee_convertsinterfaces because nothing appears to use it, andBoth_convertdoes not provide it. NowBoth_convert.Scan be supplied to satisfyCallee_converts.S.- Annotate errors returned by the async-rpc library with the name of the RPC for which the error was returned (if it's an rpc-level error) and a description of the remote side of the connection (the ip:host if connected via a network socket).
- Bring back
val rpcsin versioned_rpc modules.
113.00.00
Fixed race in
Rpcthat caused double connection cleanup.Two errors,
Connection_closedand a Writer error,(Uncaught_exn(monitor.ml.Error_((exn(\"writer error\"....)))))), occurring at the same time will cleanup the connection twice and call response_handler of open_queries twice with two different errors.(((pid 31291) (thread_id 0)) ((human_readable 2015-05-25T10:47:18+0100) (int63_ns_since_epoch 1432547238929886105)) "unhandled exception in Async scheduler" ("unhandled exception" ((monitor.ml.Error_ ((exn ("Ivar.fill of full ivar" (Full _) lib/async_kernel/src/ivar0.ml:329:14)) (backtrace ("Raised at file "error.ml", line 7, characters 21-29" "Called from file "rpc.ml", line 101, characters 8-31" "Called from file "connection.ml", line 251, characters 8-172" "Called from file "core_hashtbl.ml", line 244, characters 36-48" "Called from file "connection.ml", line 248, characters 2-278" "Called from file "async_stream.ml", line 49, characters 53-56" "Called from file "async_stream.ml", line 21, characters 34-39" "Called from file "job_queue.ml", line 124, characters 4-7" "")) (monitor (((name main) (here ()) (id 1) (has_seen_error true) (is_detached false) (kill_index 0)))))) ((pid 31291) (thread_id 0)))))
- Fixed bugs in
Rpcin which a TCP connection's reader was closed before its writer. - In
Versioned_rpc, eliminated an unnecessary Async cycle when placing RPC messages. Added
Rpc.Pipe_rpc.close_reasonandRpc.State_rpc.close_reason, which give the reason why a pipe returned by an RPC was closed.These functions take the IDs that are returned along with the pipes by the dispatch functions, so the interface of
dispatchdid not need to change.- Made
Rpc.Expert.dispatchexpose that the connection was closed, just likeOne_way.Expert.dispatch. - Expose the name of the
Versioned_rpc.MenuRPC.
112.35.00
Moved
Async_extra.Rpcto its own library,Async_kernel_rpc, and abstracted its transport layer.Async_kernel_rpcdepends only onAsync_kernel. This allowsAsync_rpcto be used in javascript or to try transports tuned for different use cases.Versioned_rpcwas moved toAsync_rpc_kernelas well.- Added
Rpc.One_waymodule, for RPCs that do not expect any response or acknowledgment. Sped up
Rpc.Connection.We have been able to send 6_000_000 (contentless) one-way messages per second under some idealized circumstances.
- In
Rpc, added an optionalheartbeat_configargument to configure the heartbeat interval and timeout. - In
Rpc, added some information toConnection_closedexceptions. In
Rpc.Implementations.create'son_unknown_rpcargument, added aconnection_stateargument to the`Callvariant.When using
Rpc.Connection.serve, one can put client addresses in theconnection_state, so this makes it possible to identify who sent the unknown RPC instead of just saying what the RPC's name and version are.- Added
Rpc.One_way.Expert, which has animplementfunction that gives direct access to the internal buffer instead of using a bin-prot reader. - Made
Rpcnot raise an exception if a connection is closed due to heartbeating. Reworked
Async_rpc_kernel'sTransportimplementation to not require atransferfunction similar toAsync_unix.Writer.transfer.Changed the RPC connection to flush the pipe when the writer is closed, which was the only behavior of
Async_unix.Writer.transferthat had been relied on.With this change, if someone closes the underlying writer by hand the pipes won't be flushed, which should be expected anyway.
Fixed an issue where "normal"
Pipe_rpcerrors caused the connection to shutdown.Such errors include querying an unknown RPC or getting an exception raised by the RPC implementation shutdown. Now such errors behave like
Rpcerrors, i.e. they are completely ignored besides being put in the return value ofPipe_rpc.dispatch.Errors that occur later in
Pipe_rpcstill cause the connection to close, since these should only occur if there is a bug somewhere.In
Rpc, connection-closing errors no longer raise top-level exceptions.One can now call
close_reason : t -> Info.t Deferred.tto get the reason the connection was closed.- Added
One_wayrpcs toVersioned_rpc. Fixed
Rpcto not write if the transport is closed.The fix doesn't check that the writer is closed, but instead ensure that we don't try to write when we shouldn't. This means that it will still fail if the user close the transport by hand, which they shouldn't do.
This change requires transport implementations to fail after they have been closed. This is different from the semantics of
Async_unix.Writer, but the latter is non-intuitive and makes it hard to check the correctness of the code. Moreover it is only required forAsync_unix.Writer.with_flushed_at_closewhich we don't use.