Assignment 2 - Add Dapr service-to-service invocation
January 9, 2025 ยท View on GitHub
Assignment goals
To complete this assignment, you must reach the following goals:
- The VehicleRegistrationService and FineCollectionService are both running with a Dapr sidecar.
- The FineCollectionService uses the Dapr service invocation building block to call the
/vehicleinfo/{licensenumber}endpoint on the VehicleRegistrationService.
This assignment targets number 1 in the end-state setup:
Step 1: Start the VehicleRegistrationService with Dapr
In assignment 1, you started all the services using uvicorn <app>. When you want to run a service with a Dapr sidecar
that handles its communication, you need to start it using the Dapr CLI. There are a couple of things you need to
specify when starting the service:
-
The service needs a unique id which Dapr can use to find it. This is called the app-id (or application Id). You specify this with the
--app-idflag on the command-line. -
Each of the services listens on a different HTTP port for requests (to prevent port collisions on localhost). The VehicleRegistrationService runs on port
6002for instance. You need to tell Dapr this port so the Dapr sidecar can communicate with the service. You specify this with the--app-portflag on the command-line. -
The service can use HTTP or gRPC to communicate with the Dapr sidecar. By default these ports are
3500and50001. But to prevent confusion, you'll use totally different port numbers in the assignments. To prevent port collisions on the local machine when running multiple services, you have to specify a unique HTTP and gRPC port per service. You specify this with the--dapr-http-portand--dapr-grpc-portflags on the command-line. Throughout the workshop, you will use the following ports:Service Application Port Dapr sidecar HTTP port Dapr sidecar gRPC port TrafficControlService 6000 3600 60000 FineCollectionService 6001 3601 60001 VehicleRegistrationService 6002 3602 60002 -
Finally you need to tell Dapr how to start the service. The services are Python services which can be started with the command
uvicorn <app>.
You will use the run command of the Dapr CLI and specify all the options above on the command-line:
-
Make sure you have started Docker Desktop on your machine and the Dapr CLI and runtime are installed (see the prerequisites).
-
Open the source code folder in VS Code.
-
Open the terminal window in VS Code and make sure the current folder is
VehicleRegistrationService. -
Enter the following command to run the VehicleRegistrationService with a Dapr sidecar:
dapr run --app-id vehicleregistrationservice --app-port 6002 --dapr-http-port 3602 --dapr-grpc-port 60002 -- uvicorn vehicle_registration:app --port 6002 -
Check the logs for any errors. As you can see, both Dapr as well as application logging is shown as output.
Now you're running a 'Daprized' version of the VehicleRegistrationService. As you might have noticed, you didn't need to change any code for this to work. The VehicleRegistrationService is still just a web API listening for requests. Only now, you've started it with a Dapr sidecar next to it that can communicate with it. This means other services can use Dapr to call this service. This is what you'll do in the next step.
Step 2: Call the VehicleRegistrationService using Dapr service invocation
In this step, you're going to change the code of the FineCollectionService so it uses Dapr service invocation to call the VehicleRegistrationService.
First you're going to change the code so it calls the Dapr sidecar:
-
Open the file
FineCollectionService/fine_collection/clients.pyin VS Code. -
Inspect the
get_vehicle_infomethod. It contains a call to the VehicleRegistrationService to retrieve the vehicle info:response = requests.get(f"{self.base_address}/vehicleinfo/{license_number}") if response.status_code == 200: return Vehicle.parse_raw(response.content)requestsis a http library which is used to invoke the VehicleRegistrationService. Its base address for consuming the API is determined by thesettings.py, which in turn reads the settings from the.envfile stored inFineCollectionService. -
Open the file
FineCollectionService/.envin VS Code.Here we see the actual value being configured. Inspect the
VEHICLE_REGISTRATION_ADDRESSsetting. You can see that in the HTTP call, the URL of the VehicleRegistrationService (running on port 6002) is used. -
The API for calling the Dapr service invocation building block on a Dapr sidecar is:
http://localhost:<daprPort>/v1.0/invoke/<appId>/method/<method-name>You can substitute the placeholders in this URL with the appropriate values so the FineCollectionService's sidecar can call the the VehicleRegistrationService, this yields the following URL:
http://localhost:3601/v1.0/invoke/vehicleregistrationservice/method/vehicleinfo/{licenseNumber}As you can see in this URL, the FineCollectionService's Dapr sidecar will run on HTTP port
3601. -
Replace the URL in the configuration file with the new Dapr service invocation URL. The line should now look like this:
VEHICLE_REGISTRATION_ADDRESS=http://localhost:3601/v1.0/invoke/vehicleregistrationservice/methodThe root URL in the settings file is replaced with the placeholder URL from step 3 up until the
<method-name>part of the URL.It's important to really grasp the sidecar pattern used by Dapr. In this case, the FineCollectionService calls the VehicleRegistrationService by calling its own Dapr sidecar! The FineCollectionService doesn't need to know anymore where the VehicleRegistrationService lives because its Dapr sidecar will take care of that. It will find it based on the
app-idspecified in the URL and call the target service's sidecar. -
Open a new terminal window in VS Code and make sure the current folder is
FineCollectionService. -
Enter the following command to run the FineCollectionService with a Dapr sidecar:
dapr run --app-id finecollectionservice --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- uvicorn fine_collection:app --port 6001 -
Check the logs for any errors. As you can see, both Dapr as well as application logging is shown as output.
Now you're going to test the application:
-
Open a new terminal window in VS Code and change the current folder to
TrafficControlService. -
Enter the following command to run the TrafficControlService:
uvicorn traffic_control:app --port 6000
The TrafficControlService does not need to run with a Dapr sidecar in this assignment. This is because it will still call the FineCollectionService over HTTP as before.
The services are up & running. Now you're going to test this using the simulation.
-
Open a new terminal window in VS Code and change the current folder to
Simulation. -
Start the simulation:
python3 simulation
You should see similar logging as before when you ran the application. So all the functionality works the same, but now you use Dapr service invocation to communicate between the FineCollectionService and the VehicleRegistrationService.
Step 3: Use Dapr service invocation with the Dapr SDK for Python
In this step, you're going to change the code of the FineCollectionService so it uses the Dapr SDK for Python to call the VehicleRegistrationService. The SDK provides a more integrated way to invoke the Dapr sidecar API.
First stop the simulation:
-
Open the terminal window in VS Code in which the Camera Simulation runs.
-
Stop the simulation by pressing
Ctrl-Cand close the terminal window by clicking the trashcan icon in its title bar (or typing theexitcommand). -
Open the terminal window in VS Code in which the FineCollectionService runs.
-
Stop the service by pressing
Ctrl-C. Keep this terminal window open and focused. -
Run the following command to install the Dapr SDK for Python:
pip3 install daprThe Dapr SDK for Python contains the
DaprClientclass that we will use to directly invoke the Dapr API. There are more components in the SDK. We will use those later in the workshop.
Now you'll change the code to use the Dapr-provided DaprClient to call the VehicleRegistrationService. In step 2 we
used the requests library to keep our application unaware of Dapr. In this step we're going to upgrade our application
to use the SDK instead.
-
Open the file,
FineCollectionService/fine_collection/clients.pyin VS Code. -
Replace the contents of the file with the following code:
from pydantic import BaseModel from dapr.clients import DaprClient class Vehicle(BaseModel): vehicleId: str make: str model: str ownerName: str ownerEmail: str class VehicleRegistrationClient: def __init__(self, base_address: str): self.base_address = base_address def get_vehicle_info(self, license_number: str) -> Vehicle: with DaprClient() as client: response = client.invoke_method( "vehicleregistrationservice", f"vehicleinfo/{license_number}", data=b'', http_verb="GET" ) return Vehicle.parse_raw(response.text())
Now the FineCollectionService is changed to use the Dapr SDK for service invocation. Let's test this.
-
If you followed the instructions in this assignment, the VehicleRegistrationService and TrafficControlService are still running.
-
Open the terminal window in VS Code in which the FineCollectionService was running.
-
Enter the following command to start the changed FineCollectionService again:
dapr run --app-id finecollectionservice --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- uvicorn fine_collection:app --port 6001
The services are up & running. Now you're going to test this using the simulation.
-
Open a new terminal window in VS Code and change the current folder to
Simulation. -
Start the simulation:
python3 simulation
You should see similar logging as before when you ran the application.
Step 4: Use Dapr observability
So how can you check whether or not the call to the VehicleRegistrationService is handled by Dapr? Well, Dapr has some observability built in. You can look at Dapr traffic using Zipkin:
-
Open a browser and go the this URL: http://localhost:9411/zipkin.
-
Click the
RUN QUERYbutton in the top right of the screen to search for traces. -
You should see the calls between the FineCollectionService and the VehicleRegistrationService. You can expand and collapse each trace and click the
SHOWbutton to get more details:
-
If you click the dependencies button and search, you will see the services and the traffic flowing between them:

Next assignment
Make sure you stop all running processes and close all the terminal windows in VS Code before proceeding to the next assignment.
Go to assignment 3.