Skip to content

Latest commit

 

History

History
284 lines (205 loc) · 7.44 KB

TODO.md

File metadata and controls

284 lines (205 loc) · 7.44 KB

TODO

  • Update the Stream.md document

    • to reflect the new classes
  • Handle event payload serialization

    • the pack method might not work
    • look into JSON feature for to_JSON methods or something
  • Everything needs controlled shutdown, not DESTROY

    • this might make it possible to remove the schedule callback feature in the scheduler
      • it is only used internally for:
        • scheduling init
          • this could be done another way
        • scheduling despawn and child stop
          • which could be converted to chained signals/events

Intervals

Think about this more.

    $ctx->schedule(
        event => event( *Hello::Goodbye => "Cruel World" ),
        for   => $hello,
        after => 2,
    );

    $ctx->schedule(
        event => event( *Hello::Goodbye => "Cruel World" ),
        for   => $hello,
        every => 2, #interval
    );

Remoting

Implement Node connection protocol

Node1 = perl start-note.pl --at 3000 Node2 = perl start-node.pl --at 3001 --connect 3000

Node2 - connects to Node1

Node1 - accepts connection from Node2 - sends WelcomeMessage to Node2

Node2 - reads WelcomeMessage - sends WelcomeResponse to Node1

Node1 - reach WelcomeResponse - sends WelcomeRepsonse to Node2

WelcomeMessage - container sender for response

WelcomeResponse - contains list of important PIDs and their addresses

Await Blocks

Make await blocks support two things:

  • multiple event cases
  • timeouts (which are delivered as messages to the block)

This means we need to manage the timeout, so we have to cancel if we get a match.

  • also decide how Timeout events will look.
    • do we use strings?
    • known constant (ex: *Acktor::Scheduler::Timers::Timeout)?
    • import a known constant so you can say *Timeout
    • is this a case for Protocols?
use Acktor::Behaviors;

class HTTPServer :isa(Acktor) {

    method Request :Receive ($method, $url) {
        sender->send( event *Response => '200 OK' );
    }
}

class HTTPClient :isa(Acktor) {

    field $server;

    method Request :Receive ($url) {

        $server->send( event *HTTP::Request => ( GET => $url ) );

        await { timeout => 10 },
            *HTTPServer::Response => method :Receive ($body) {
                # ... handle the body
            },
            'Timeout' => method :Receive {
                # timeout!
            }
        ;
    }
}


$client->send(
    event *HTTPClient::Request, ('http://www.google.com')
);

Would love it if it could be this:

class HTTPClient :isa(Acktor) {

    field $server;

    method Request :Receive ($url) {

        $server->send( event *HTTP::Request => ( GET => $url ) );

        await { timeout => 10 },
            method :Receive(*HTTPServer::Response) ($body) {
                # ... handle the body
            },
            method :Receive(*Timeout) {
                # timeout!
            }
        ;
    }
}

But the attributes do not work on methods at runtime, so that sucks.

Protocols

Add protocols, that create the event symbols and use the Receive attribute to direct messages to a given method.

class Acktor::Protocol::HTTP {
    use Acktor::Protocol;

    event *Request;
    event *Response;
}

class HTTPServer :isa(Acktor) {
    use Acktor::Behaviors;
    use Acktor::Protocol => 'HTTP';

    method Request :Receive(*HTTP::Request) ($method, $url) {
        sender->send( event *HTTP::Response => '200 OK' );
    }
}

class HTTPClient :isa(Acktor) {
    use Acktor::Behaviors;
    use Acktor::Protocol => 'HTTP';

    field $server;

    method Get :Receive ($url) {

        $server->send( event *HTTP::Request => ( GET => $url ) );

        await *HTTP::Response => method :Receive ($body) {
            ...
        };
    }
}


$client->send(
    event *HTTPClient::Get, ('http://www.google.com')
);

TODO (examples)

TO ADD (MAYBE)

Futures

A future will return a promise (Thenable) that is connected to an Actor instance. The Actor instance sends the message and awaits the result, assuming the actor being called will respond to sender. When this actor instance gets a result, then it resolves the promise it is attached to.

The advantage of this is that you can launch multiple futures at once, and then collect them using the collect function turn them into a single promise.

Another advantage of the future is that it does not affect the actors state. Whereas await affects the state of the instance via become.

class HTTPClient :isa(Acktor) {
    use Acktor::Behaviors;

    field $server;

    method Request :Receive ($url) {

        my $f1 = future[*HTTP::Response] => (
            to     => $server,
            event  => event( *HTTP::Request => ( GET => $url1 ) ),
            timout => 3,
        );

        my $f2 = future[*HTTP::Response] => (
            to     => $server,
            event  => event( *HTTP::Request => ( GET => $url2 ) ),
            timout => 5,
        );

        # this is async, it does not block
        collect($f1, $f2)
            ->on_success(method ($results) { ... })
            ->on_error(method ($error)   { ... })
            ->on_timeout(method { ... });
    }
}

MISC (NEEDS MORE THINKING)