Skip to content

Information about LocationRegisteredEvent

The function description is in https://majority.atlassian.net/browse/MIB-6064.

In Locations service, we capture events below:
KycSuccessfullyVerifiedEvent and AccountHolderProfileUpdatedEvent: when Locations service receives these events, it will save user’s address to Locations database and get coordinate from google place, and then save coordinate to Locations database. Because user’s address is unique for each user, the coordinate is not cached in Redis.

TransactionCompletedEvent (TransactionType is TransactionType.PosMoneyLoad or TransactionType.PosPurchase or TransactionType.AtmWithdrawal), ExternalCardUpdatedEvent and CardWasShippedEvent: when locations service receives these events:
1. it will get coordinate from google place for the address in the event and cache the addresskey and coordinate to Redis.
2. get user address’s coordinate from Locations database
3. then calculate the distance between event’s address and user address.
4. Send LocationRegisteredEvent

When KycSuccessfullyVerifiedEvent is received, Locations service also send LocationRegisteredEvent with DistanceToKycAddress=0.

The requests to Google place come from:

  1. Get coordinate for user’s kyc address, the result is already saved in locations database, no duplicate request for same address.
  2. Get coordinate for address in TransactionCompletedEvent/ ExternalCardUpdatedEvent/ CardWasShippedEvent, the result is cached in Redis, the cached object will be expired after 10 days (global-redis-config.json), no duplicate request for same address within 10 days.
    Because some addresses’ formats are not valid, getting coordinate from google place will fail. In https://majority.atlassian.net/browse/MIB-6624 we already cached or saved an empty coordinate (both Latitude and Longitude are 0), so no duplicate requests for invalid address. The ticket was deployed on 2022-11-03.

About backfill LocationRegisteredEvent for historic transactions:

Because there are 2 298 422 old transactions to backfill, it may cause big cost from google place. I have not done it yet.
If it needs to be done, an integration test can be created in Locations, an example is:

[TestClass]
public class BackfillLocationRegisteredEvent: LocationsIntegrationTest
{
    private  RandomNumberGenerator _random;
    [TestMethod]
    public async Task SendEvent()
    {
        _random = RandomNumberGenerator.Create();
        using var fileReader = new StreamReader(@"C:\Users\LingZhang\Documents\Locations\backfill_merchants_userid.csv");
        using var fileWriter = new StreamWriter(@"C:\Users\LingZhang\Documents\Locations\processed_transactionIds.csv");
        fileReader.ReadLine();
        var transactionLine = fileReader.ReadLine();
        var count = 0;

        while (transactionLine != null && count < 1)
        {
            var transactionInfo = transactionLine.Split(",");

            var transactionId = transactionInfo[0];

            var userId = new Guid(transactionInfo[1]);

            var eventId = new Guid(transactionInfo[2]);

            var eventName = transactionInfo[3];

            var zipCode = transactionInfo[4];

            var city = transactionInfo[5];

            var state = transactionInfo[6];

            count++;

            FireLocationRegisteredEventMessage message = new FireLocationRegisteredEventMessage
            {
                UserId = userId,
                EventId = eventId,
                EventName = eventName,
                ZipCode = zipCode,
                City = city,
                State = state
            };

            await MessageBus.Schedule(message, JitteredDate());

            fileWriter.WriteLine(transactionId.ToString());
            transactionLine = fileReader.ReadLine();
        }

    }

    private DateTime JitteredDate()
    {
        var jitter = _random.Next(10, 60);

        return DateTime.UtcNow.AddSeconds(jitter);
    }

}

Some extra work needed to send the event to production service bus:
1. Change service bus connection in secret.ps1 to prod connection string (get from Moham)

  1. By default, when integration test sends event, its topic name contains machine name as prefix, so the event can’t be captured by service in prod. I fixed it by commenting out some platform code in MessageHelpers.cs and MessageService.cs, then compile Rebtel.Core.Infrastructure.EventBus and Majority.Platform.Testing.MessageBus with same assembly version in nuget package, then copy the two .dlls into nuget package folder.

       public string FormatTopicName(string topicName)
      {
          //if (_hostingEnvironment.IsDevelopment() && GetUniqueAgentName() != null)
          //{
          //    topicName = $"{Environment.MachineName}-{GetUniqueAgentName()}-{topicName}";
          //}
          //else if (_hostingEnvironment.IsDevelopment())
          //{
          //    topicName = $"{Environment.MachineName}-{topicName}";
          //}
    
          return topicName.ToLowerInvariant();
      }
    
    1. You also need to comment out event handler registering code otherwise your local service will receive events from prod.
  2. Since it’s dangerous to send event to prod from local integration test, make sure only this one integration test will be run. It’s better to delete all other tests before running this one.

  3. Should add builder.ConfigureTestMessageBus(o => o.UseInMemoryMessageBus = false); in LocationsIntegrationTest class