6

I am working on a program in golang, which I am sructuring based on Hexagonal Architecture. I think I have my head wrapped mostly around the idea, but there is something I just can't figure out.

The function of the program is to monitor multiple IP cameras for alarm events, which a receiver can receive a live stream of alarm events over a HTTP2.0 PUSH REQUEST. (Just in-case thats not the technical term, my service establishes a TCP/HTTP connection from a GET request and keeps it open, and when the cameras triggers an alarm event, the camera pushes it back to the services)

Layers of Architecture

Adaptors

  • HTTP Handler
  • In-memory JSON Store

Ports

  • DeviceService Interface
  • EventService Interface
  • DeviceRepo Interface
  • EventRepo Interface

Services

  • DeviceService
  • EventService

Domain

  • DeviceDomain
  • EventDomain

The user adds a device to the system via API, the request includes the desired monitoring schedule (When the receiver should start and stop daily) and url.

A scheduler is responsible to periodically checking if a receiver is meant to be started based on its schedule. If it's meant to be running for a device it starts a receiver for that device.

The receiver establishes connection to the IP camera and loops over the alarm event stream processing the alarm events and passing them to the EventService.

The EventService receives the event, and is responsible for handling the event, based on the domain logic, and decides to send an email or ignore it. It also saves all events to the eventrepo.

The two parts of code i'm not sure where they sit is the scheduler and receiver. So should they be; a. Both in the same package and placed at the Adaptors layer b. The receiver in the Adaptors layer and the scheduler in the Service layer c. Both scheduler and receivers in the Service layer?

I am just confused, as the receiver isn't started by the user directly, but started by a running loop which continually checks a condition. But I also might have different receivers for different brands of cameras. Which is an implementation detail, which means the receiver should be in the Adaptors layer. Which makes me think option b is best.

I'm possibly over thinking it, but let me know what you all think the best option is or suggest a better one.

lukerobbo
  • 71
  • 4

3 Answers3

2

If it can help you, my design would be as follow:

Driver actors:

  • Human User: Interacts with the app using a driver port: "for adding devices"
  • Device (IP camera): Sends alarm events to the app using another driver port: "for receiving alarm events"

Driven actors:

  • Device (IP camera): The app interacts with the device using the driven port "for checking device", in order to start and stop it daily, according to the schedule of the device.
  • Warning Recipients: The app sends an email to them when an alarm event is received and it is not ignored.
  • Alarm Event Store: For persisting the alarm events the app receives.

The app ("Alarm Monitor") does the following business logic:

  • Maintains a collection of devices it has to monitor ("for adding devices").
  • It has a "worker" (the scheduler) that periodically checks the devices status and starts/stops them according to the schedule of the device.
  • It handles alarm events received from the devices. When an alarm event is received, the app either sends an email or ignore it. And stores the event in a repository.

So for me:

  • The scheduler is part of the business logic.
  • The receiver is the adapter of a device. It deels with http stuff.

Here is the picture:

enter image description here

choquero70
  • 4,470
  • 2
  • 28
  • 48
1

"A scheduler is responsible to periodically checking if a receiver is meant to be started based on its schedule"

Ultimately it doesn't really matter to the application whether a human presses an "autoStartReceivers" button peridically or it's done by a scheduling process. Therefore that's an infrastructure concern and the scheduler is a driver adapter. You'd probably have a ReceiverService.autoStartReceivers service command that would be invoked by the scheduler periodically.

Now for the Receiver I'd say it depends on the implementation. If the Receiver doesn't know about infrastructure/vendor-specific details, but only does coordination then it may belong to the application/service layer.

For instance perhaps the receiver works with an abstract EventSource (HTTP, WebSockets, etc.) and uses an EventDecoder (vendor-specific) to adapt events and then relays them to an EventProcessor then it really only is doing orchestration. The EventSource & EventDecoder would be adapters. However if the Receiver knows about specific infrastructure details then it becomes an adapter.

Ultimately all the above is supporting logic for your core domain of event processing. The core domain logic wouldn't really care how events were captured and probably wouldn't care either how resulting actions are carried on. Therefore, your core domain in it's most simplistic form is probably actions = process(event) pure functions.

plalx
  • 42,889
  • 6
  • 74
  • 90
  • Correct the `Receiver` will be based on vendor-specific details. The idea is to have the ability to swap out the `Receiver` with a different one if I were to change the device, and the `Receiver` will talk to the `EventService`. So the this makes sense that the `Receiver` is a driver adaptor. But what I forgot to mention was I would like the ability to control the `Receiver`, stop, start. Which makes it then sound like a driven adaptor? Can an adaptor be both a driven and driver adaptor? or should there be another driven adaptor say `ReceiverManager` that has a way to talk to the `Receivers`? – lukerobbo Aug 17 '21 at 23:50
  • Of course an adapter can be driver and driven at the same time. It would have a configurable dependency on a driver port, and also it would implement a driven port. In the pic of my solution the driven adapter for the ip camera is the receiver. – choquero70 Aug 20 '21 at 10:30
1

a. Both in the same package and placed at the Adaptors layer

b. The receiver in the Adaptors layer and the scheduler in the Service layer

c. Both scheduler and receivers in the Service layer?

The receiver and scheduler are both adapters. I don't think that they must be placed in the same package, but you can do that. So a is the best answer for me, because...

The receiver connects your application with an external device - the ip camara. Thus the receiver is an adapter for the EventService port.

The scheduler indirectly manages the lifecycle of the receiver through the DeviceService port. It enables or disables an ip camara and this leads to a connect and disconnect of the receiver.

From the perspective of your application core the scheduler is just another adapter that tells the DeviceService port to enable or disable some ip camara. This could also be done by a user who clicks on a button in the UI. The scheduler is just a technical assistance for the user which executes tasks that the user wants based on a schedule. Thus the scheduler is also an adapter.

René Link
  • 48,224
  • 13
  • 108
  • 140