This R2R module pre-evaluates the eligibility to receive travel incentives. The incentives are associated with travel offers. The current version supports the incentives listed in the following table:
Incentive | Description |
---|---|
10%Discount | The incentive is associated with a travel offer item if at least one ride-sharing leg is included in any travel offer item. |
20%Discount | The incentive is associated with a travel offer item if the offered item contains at least one ride-sharing leg and the passenger completed at least three ride-shares. The counter of completed ride-shares is set to zero after allocating the incentive. |
FreeSeat | The incentive is associated with a travel offer if at least one other passenger booked at least one of the ride-shares included in the travel offer item. |
For a given request_id, the corresponding list of travel offer items and the transport modes associated with legs are obtained from the offer-cache. Based on this data, the presence of ride-sharing legs is analysed in the method checkFulfilled() of the class RideSharingInvolved implemented in the script rules.py.
For a given request_id, the corresponding list of travel offer items, Traveler ID and the transport modes associated with legs are obtained from the offer-cache. If an offer item contains a ride-sharing leg, Traveler ID is used to request the Agreement Ledger module to obtain information about the eligibility to receive 20%Discount incentive. Otherwise, it is concluded that offer item is concluded to be not eligible for this incentive. The evaluation is implemented by the method checkFulfilled()_ of the class ThreePreviousEpisodesRS implemented in the script rules.py.
For a given request_id, the corresponding list of trip leg IDs and the corresponding transport modes are obtained from the offer-cache. If an offer item contains a ride-sharing leg, Trip leg ID is used to request the Agreement Ledger module to obtain information about the eligibility to receive FreeSeat incentive, and it is outputted. Otherwise, it is concluded that offer item is concluded to be not eligible for this incentive. The evaluation is implemented by the method checkFulfilled()_ of the class TwoPassShared implemented in the script rules.py.
This step requires registration of the service at the Agreement Ledger Login end-point. Afterwards, the Incentive provider module is assigned a secret. Valid values need to be defined in the configuration file incentive_provider_api.conf. The URL can be set in the section agreement_ledger_api:
[agreement_ledger_api]
auth_url = URL_OF_AUTHENTICATION_AGREEMENT_LEDGER_END_POINT
The secret can be set in the section auth:
[auth]
basic_secret = SECRET
Incentive provider module is implemented by classes that are presented in the following figure. .
Script communicators.py
The script implements communicators. A Communicator is a class ensuring interaction with an external service.
The class Communicator is an abstract class serving as a common predecessor for classes that implement communication with external services.
The class AgreementLedgerCommunicator ensures sending a request to the Agreement Ledger. It implements reading of URLs and of other parameters from the config file incentive_provider_api.conf. Further, it creates an instance of the class RequestObtainer that ensures the execution of requests. The request is executed by the method accessRuleData().
The class OfferCacheCommunicator ensures sending a request to the offer-cache. It reads the host address and port from the config file incentive_provider_api.conf and utilizes them to establish a connection with the offer-cache. The request to obtain data from the Offer-Cache is executed by calling the sequence of methods that are implemented by this class. By calling the method accessRuleData(), the request to get data from the offer-cache is executed. Depended on the level of requested data, methods read_data_from_offer_cache() and redis_request_level_item() are called. The method read_data_from_offer_cache() ensures calling of the method read_data_from_cache_wrapper() from the package r2r_offer_utils that for a given request_id reads the required attribute values at the levels of offer item and trip leg. The method redis_request_level_item() reads the required values of attributes at the level of the mobility request.
Script AL_requester.py
The script implements classes ensuring interaction (authentication and sending of request) with external services (i.e., Agreement Ledger).
The class implements acquisition and renewal of the communication token from the login in end-point. The URL and headers need to be provided as parameters. If more requests simultaneously ask for an authentication token from AL api, only the first is allowed and the others wait. This parallelism is implemented by the binary Semaphore mechanism.
The class executes requests to an external end-point. It reads the parameters of the authentication end-point from the configuration file incentive_provider_api.conf. It expects an instance of the class AuthTokenObtainer that ensures the acquisition of the communication token. The instances of RequestObtainer should share a single instance of AuthTokenObtainer to allow token sharing. The method load_request() executes authentication and the request to the external service. The handling and logging of error situations is separated in the method checkResponse().
The class is used to wrap up the response of methods that ensure communication with external services. In addition, it takes care of logging the errors, which is the functionality that is also sometimes used, and an instance of the class is created for this purpose.
Script rules.py
The script implements rules that pre-evaluate the eligibility of offer items to be assigned an incentive.
This class is a common predecessor of classes that implement rules. It is expected that every rule will be implemented by a class inherited from the class Rule. The pre-evaluation is implemented by the method checkFulfilled().
The class pre-evaluates the eligibility to receive the FreeSeat incentive.
The class pre-evaluates the eligibility to receive the 10%Discount incentive.
The class pre-evaluates the eligibility to receive the 20%Discount incentive.
The class maintains the results of a rule evaluation for later use, e.g., for the consistency check or for the final output of results. An instance of the class Incentive is created for every offered item and every type of incentive.
Script incentive_provider.py
The script implements the upper layer of the Incentive provider module. It takes care of the initialization of rules that are applied in the pre-evaluation process and the initialization of the incentives. The script implements the way how the rules are applied and the consistency check that ensures that only mutually compatible incentives are returned for each offered item.
The class IncentiveProvider implements the method getEligibleIncentives() that executes each rule on each offer item, the method consistencyCheck() that implements the constraints defining the mutual compatibility of incentives. Currently, to demonstrate this functionality, the incentives 10%Discount and 20%Discount are considered to be mutually incompatible and if rules assigned both these incentives to a single offer item, during the consistency check the eligibility for 10%Discount is cancelled.
The class IncentiveProviderManager ensures correct initialization of the Incentive provider and implements the method getIncentives() that calls the methods implemented by the class IncentiveProvider to execute the pre-evaluation of incentive eligibility.
Before launching the service on the localhost, make sure that in the configuration file incentive_provider_api.conf, section cache, the host is set to value localhost. Thi is required for establishing the connection to the Offer-cache.
[cache]
host = localhost
port = 6379
The module "Incentive provider" can be launched locally from the terminal by running the script "incentive_provider_api.py":
2022-01-17 11:29:45 - incentive_provider_api - INFO - config loaded successfully
* Serving Flask app 'incentive_provider_api' (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5011/ (Press CTRL+C to quit)
The incentive provider was configured to run by default on the port 5011.
Before launching the service on the Docker, make sure that in the configuration file incentive_provider_api.conf, section cache, the host is set to value cache. This is required for establishing the connection to the Offer-cache.
[cache]
host = cache
port = 6379
- Go to the incentive-provider directory and build the docker image
$ docker-compose build
- Run the docker container
docker-compose up
Starting incentive-provider ... done
Attaching to incentive-provider
incentive-provider | * Serving Flask app 'incentive_provider_api.py' (lazy loading)
incentive-provider | * Environment: production
incentive-provider | WARNING: This is a development server. Do not use it in a production deployment.
incentive-provider | Use a production WSGI server instead.
incentive-provider | * Debug mode: off
incentive-provider | 2022-01-27 07:10:51 - incentive_provider_api - INFO - config loaded successfully
incentive-provider | * Running on all addresses.
incentive-provider | WARNING: This is a development server. Do not use it in a production deployment.
incentive-provider | * Running on http://172.18.0.4:5000/ (Press CTRL+C to quit)
Please note that the Incentive provider container connects to the docker network trias-extractor_offer-enhancer-net. to be able to communicate with other modules. Hence, this network must be established prior to running the incentive-provider container. Such a network is created when the trias-extractor is launched in the docker environment.
Example of the curl command to receive a JSON file with information about the incentives associated with the travel offers included in the request, which is identified by < request_id >:
curl -X GET "http://127.0.0.1:5011/incentive_provider/?request_id=< request_id >"
Example of the returned JSON file:
{
"36e5c5b9-b434-40c4-8017-9ec79578813a": {
"10discount": true,
"trainSeatUpgrade": true,
"20discount": false
},
"ef9012a8-918b-4e20-a724-rs1": {
"10discount": true,
"trainSeatUpgrade": true,
"20discount": false
},
"731d2c82-e158-4d87-8cd6-df9bbcc647e6": {
"10discount": false,
"trainSeatUpgrade": false,
"20discount": false
},
"5c08395c-7efc-4418-a2dc-c2794e7120f6": {
"10discount": true,
"trainSeatUpgrade": true,
"20discount": false
},
"c421d948-8741-4b33-8797-3871ec8b3b7f": {
"10discount": false,
"trainSeatUpgrade": false,
"20discount": false
}
* Closing connection 0
(base)
The Incentive provider returns the JSON file as exemplified in the Section Requesting Incentive provider.
If the request is successfully processed, the JSON file contains for each travel offer a list of all incentives and the value "true" or "false" indicating the result of the incentive eligibility pre-evaluation.
For the correct functionality of the Incentive provider the functional connection to the Offer-cache component is essential. So if there is no information associated with the provided request_id in the Offer-cache or if the connection to the Offer cache is not functional the Incentive Provider returns the following JSON file together with the HTTP code 200:
"offers": {
"no_offer": {
"10discount": false,
"trainSeatUpgrade": false,
"20discount": false
}
}, 660-1326-4b6b-bf00-132ec7e576de"
* Closing connection 1
}(base)
In a case, if the authentication or a request to the Agreement Ledger fails, the eligibility to receive the corresponding incentives is set to "false" and the HTTP status code 200 is returned. The information about the experienced errors is reported to the standard output and logged to the file error.log.
In some cases HTTP code 500 can be returned:
- if there is no request_id provided in URL parameters,
- if an unexpected exception emerged when processing incentives,
- if the writing of the results to cache failed.
- The communication with the Agreement Ledger could be faster if run in parallel. However, the preliminary experiments showed favourable response times of the Agreement Ledger, and thus there was no need to further optimise the code.