Documentation
Hexagonal architecture
This pattern is also known as Ports and Adapters, or Onion architecture. While the latter would be the most accurate (the separation between the layers is what matters, not the 6 sides), it's usually drawn with hexagons and so the name stuck.
The purpose of the hexagonal architecture in contrast with, say, a simple layered architecture, is to separate
the domain logic from the application logic.
As you do not want to be coupling things like HTTP requests, database queries and domain model modifications
together, you'll need a way to divide them.
To achieve this separation, an object is only allowed to interact with objects in the same layer or deeper.
It's never allowed to interact with layers further to the outside.
You'll put most of the domain logic inside the domain model, while the domain services are
responsible for the bits of logic that span multiple aggregates.
The controllers manage you HTTP requests and the repositories
[1]Sometimes people put repository interfaces inside the domain service layer (though never the implementations).
In my opinion this is cheating, as there's no point in pretending that interacting with an interface will really not perform any actual object storage logic.
your queries of course. That leaves the application services to tie everything together.
If you have logic that spans multiple bounded contexts, you'll usually want the communication to go via events
and that's where you'll need event handlers. They function a bit like a controllers, but react to
events instead of HTTP requests.