Petabridge.Cmd Clients
Petabridge.Cmd offers two types of clients to consumers of the software:
- The
pbm
command line interface (CLI) - which has detailed installation and usage instructions and - Programmatic clients which can be invoked via C# or F# against an active
PetabridgeCmd
host installation.
pbm
CLI
Rather than reproduce a lengthy document on how to work with the pbm
CLI here, we have a dedicated piece of documentation for it here: pbm
installation and usage instructions.
IPbmClient
Programmatic Client
In some cases you may want to be able to invoke Petabridge.Cmd programmatically. As of Petabridge.Cmd 1.0+ we now support the ability to do this:
- In-process, running inside the same process as the
PetabridgeCmd
host and - From a remote process, using the same TCP port that the
PetabridgeCmd
host uses to accept incoming connection requests.
In both instances, you will create a handle that allows you to interact with Petabridge.Cmd that implements the IPbmClient
interface and uses Akka.Streams Source<CommandResponse>
to give you a stream of responses you can consume programmatically.
Creating In-Process IPbmClient
To create an in-process IPbmClient
, we must first start the Petabridge.Cmd host normally:
// create a Petabridge.Cmd host from our ActorSystem
var pbmHost = PetabridgeCmd.Get(Sys);
// start the host
pbmHost.Start();
If we want to create an "in-process" client, meaning one that runs in-memory inside the same process as the host, we just call the PetabridgeCmd.StartClient
method - which will asynchronously return an IPbmClient
instance for us to use:
// create a client
IPbmClient client = await pbmHost.StartLocalClient();
// generate some logs that will show up instead the stream
foreach (var i in Enumerable.Range(1, 10))
{
Log.Info("{0}", i);
}
// invoke a "log peek" command, just like you would on CLI
CommandSession session = await client.ExecuteTextCommandAsync("log peek");
// grab a hold of the Akka.Streams materializer from ActorSystem
var materializer = Sys.Materializer();
// pipe the Akka.Streams Source<CommandResponse> to a Sink<CommandResponse>
// in this case, we're just going to send everything to a TestActor.
//
// This Akka.Streams "graph" can be materialized into a Task, which will
// complete once the stream is marked as complete by the Petabridge.Cmd host.
var completionTask = session.Stream.RunForeach(rsp =>
{
TestActor.Tell(rsp);
}, materializer);
// and we can validate that the TestActor received at least one CommandResponse
var response = ExpectMsg<CommandResponse>();
// a client can also cancel the stream using the KillSwitch included
// inside the CommandSession object
session.KillSwitch.Shutdown();
// once either of those two events occur, the Task returned earlier
// will be complete
await completionTask;
From here we can invoke a log tail
command and receive a CommandSession
object in response. The CommandSession
contains two important handles for us:
- A
Source<CommandResponse>
- an Akka.Streams source that we can use to consume all of the replies sent from a command invocation. Some commands will stream replies indefinitely, i.e.cluster tail
,log tail
, and others. Other commands will send back a finite number of responses and terminate on their own. - A
UniqueKillSwitch
- an Akka.Streams handle that the client can use to terminate the response stream even in the server isn't finished yet.
Important
Each IPbmClient
can run multiple, concurrent commands interactively with a single PetabridgeCmd
host - this is a recent addition made as part of the Petabridge.Cmd 1.0 release.
Create Remote Process IPbmClient
Running a remote IPbmClient
looks almost exactly the same as running an in-process client. The difference is: we have to pass in an EndPoint
that the client will use to contact the PetabridgeCmd
host over the network. This process will use the exact same port used by the pbm
CLI - see the "host configuration" section for more details on how this works.
// create a Petabridge.Cmd host from our ActorSystem
// host is configured to run on port 11555 via HOCON
var pbmHost = PetabridgeCmd.Get(Sys);
// start the host
pbmHost.Start();
Our host is running on its own ActorSystem
, bound to port 11555 via its HOCON configuration. We are going to create a second ActorSystem
in a separate process and remotely connect to it on that port with a remote IPbmClient
.
// create client ActorSystem
using ActorSystem clientSystem = ActorSystem.Create("ClientSystem");
// grab copy of the PetabridgeCmdClient extension (Petabridge.Cmd.Common NuGet package)
var clientExt = PetabridgeCmdClient.Get(clientSystem);
// create IpEndPoint or DnsEndPoint for contacting remote host
// either one of these would work
var ip = new IPEndPoint(IPAddress.Loopback, 11555);
var dns = new DnsEndPoint("localhost", 11555);
// start a new IPbmClient attached to one of these EndPoints
// by default this operation will time out in 5 seconds.
// you can extend that by passing in a custom CancellationToken
IPbmClient remoteClient = await clientExt.StartRemoteClient(ip);
Note
The PetabridgeCmdClient
class can be found inside the Petabridge.Cmd.Common
NuGet package - and that's the only NuGet package you need to install in order to create a remote IPbmClient
instance.
Once we've connected to our remote PetabridgeCmd
, running our IPbmClient
is identical to how we work with our in-process client:
// generate some logs that will show up instead the stream
foreach (var i in Enumerable.Range(1, 10))
{
Log.Info("{0}", i);
}
// invoke a "log peek" command, just like you would on CLI
CommandSession session = await remoteClient.ExecuteTextCommandAsync("log peek");
// grab a hold of the Akka.Streams materializer from ActorSystem
var materializer = Sys.Materializer();
// pipe the Akka.Streams Source<CommandResponse> to a Sink<CommandResponse>
// in this case, we're just going to send everything to a TestActor.
//
// This Akka.Streams "graph" can be materialized into a Task, which will
// complete once the stream is marked as complete by the Petabridge.Cmd host.
var completionTask = session.Stream.RunForeach(rsp =>
{
TestActor.Tell(rsp);
}, materializer);
// and we can validate that the TestActor received at least one CommandResponse
var response = ExpectMsg<CommandResponse>();
// a client can also cancel the stream using the KillSwitch included
// inside the CommandSession object
session.KillSwitch.Shutdown();
// once either of those two events occur, the Task returned earlier
// will be complete
await completionTask;
Network Issues
In the event that the remote server disconnects from the client, the IPbmClient.IsAvailable
property will return false
and all of the Akka.Streams graphs connected to Source<CommandRepsonse>
s associated with each CommandSession
for that client will all be completed immediately and you will receive no further messages from the server.
You will need to recreate a new IPbmClient
instance if you wish to reconnect to the server and resume interacting with it.