Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/actor #12

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open

Conversation

jeremylcarter
Copy link

@jeremylcarter jeremylcarter commented Nov 4, 2023

Please provide feedback.

To get the DI to work for Actors the ActorManager from the Dapr SDK had to be monkey patched. This is obviously something we don't want to do, but until I make a PR to allow a "hook" into the Dapr SDK there is no other way.

The next problem is that the ActorClient's new up a HttpClient for every new invocation to each actor type. This is awful and I have found the offending section of the Dapr SDK and will have to submit a PR for that too.

An example actor is:

import { Inject } from '@nestjs/common';
import { DaprActor } from '../../lib';
import { StatefulActor } from '../../lib/actors/stateful.actor';
import { CacheService } from './cache.service';

export abstract class CounterActorInterface {
  abstract increment(): Promise<void>;
  abstract getCounter(): Promise<number>;
}

@DaprActor({
  interfaceType: CounterActorInterface,
})
export class CounterActor
  extends StatefulActor
  implements CounterActorInterface
{
  @Inject(CacheService)
  private readonly cacheService: CacheService;

  counter: number;

  async onActivate(): Promise<void> {
    this.counter = 0;
    return super.onActivate();
  }

  async increment(): Promise<void> {
    this.counter++;
    // Use a NestJS service as an example.
    // Share in memory state between actors on this node.
    await this.cacheService.increment('total');

    await this.setState('counter', this.counter);
    await this.saveState();
  }

  async getCounter(): Promise<number> {
    const counter = await this.getState('counter', 0);
    this.counter = counter;
    return counter;
  }
}

And a typical NestJS controller can now just call the ActorClient to invoke actors, even if they are on other nodes.

@Controller('counter')
export class CounterController {
  constructor(private readonly actorClient: DaprActorClient) {}

  @Post(':id/increment')
  @HttpCode(204)
  increment(@Param('id') id: string): Promise<void> {
    return this.actorClient.getActor(CounterActorInterface, id).increment();
  }

  @Get(':id')
  @HttpCode(200)
  get(@Param('id') id: string): Promise<number> {
    return this.actorClient.getActor(CounterActorInterface, id).getCounter();
  }
}

Copy link
Owner

@nad-au nad-au left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. My only comment would be around testing. In the examples folder there's a docker compose file which stands up a complete dockerised dapr instance without requiring the dapr cli, which I note you've annotated the usage in the tests. Using the docker compose might be useful if you want to use GitHub Actions CI to avoid manual test runs.

Aside from that happy to approve. Also, I'm unlikely to be able to support this code in the short-term - I'm happy to transfer ownership.

@nad-au
Copy link
Owner

nad-au commented Nov 23, 2023

Once this is merged, let me know. Happy to create a pipeline - I'm doing a lot of work in CI atm

@jeremylcarter
Copy link
Author

Let me sort out the testing part. I'll ensure the docker side is working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants