diff --git a/Core/Resgrid.Services/SubscriptionsService.cs b/Core/Resgrid.Services/SubscriptionsService.cs index 9e6040ac..ece7d93c 100644 --- a/Core/Resgrid.Services/SubscriptionsService.cs +++ b/Core/Resgrid.Services/SubscriptionsService.cs @@ -56,26 +56,34 @@ public SubscriptionsService(IPlansRepository plansRepository, IPaymentRepository if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey)) { - var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl) + try { - MaxTimeout = 200000 // ms - }; + var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl) + { + MaxTimeout = 5000 // ms — fail fast so callers (e.g. Twilio webhooks) don't exceed their own timeouts + }; - var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson()); - var request = new RestRequest($"/api/Billing/GetCurrentPlanForDepartment", Method.Get); - request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey); - request.AddHeader("Content-Type", "application/json"); - request.AddParameter("departmentId", departmentId, ParameterType.QueryString); + var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson()); + var request = new RestRequest($"/api/Billing/GetCurrentPlanForDepartment", Method.Get); + request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey); + request.AddHeader("Content-Type", "application/json"); + request.AddParameter("departmentId", departmentId, ParameterType.QueryString); - var response = await client.ExecuteAsync(request); + var response = await client.ExecuteAsync(request); - if (response.StatusCode == HttpStatusCode.NotFound) - return freePlan; + if (response.StatusCode == HttpStatusCode.NotFound) + return freePlan; - if (response.Data == null) - return freePlan; + if (response.Data == null) + return freePlan; - return response.Data.Data; + return response.Data.Data; + } + catch (Exception ex) + { + Framework.Logging.LogException(ex); + return freePlan; + } } return freePlan; diff --git a/Web/Resgrid.Web.Services/Controllers/TwilioController.cs b/Web/Resgrid.Web.Services/Controllers/TwilioController.cs index c33b7f14..57ffeb96 100644 --- a/Web/Resgrid.Web.Services/Controllers/TwilioController.cs +++ b/Web/Resgrid.Web.Services/Controllers/TwilioController.cs @@ -143,12 +143,18 @@ public async Task IncomingMessage([FromQuery] TwilioMessage reques if (departmentId.HasValue) { - var department = await _departmentsService.GetDepartmentByIdAsync(departmentId.Value); - //var textToCallEnabled = await _departmentSettingsService.GetDepartmentIsTextCallImportEnabledAsync(departmentId.Value); - //var textCommandEnabled = await _departmentSettingsService.GetDepartmentIsTextCommandEnabledAsync(departmentId.Value); - var dispatchNumbers = await _departmentSettingsService.GetTextToCallSourceNumbersForDepartmentAsync(departmentId.Value); - var authroized = await _limitsService.CanDepartmentProvisionNumberAsync(departmentId.Value); - var customStates = await _customStateService.GetAllActiveCustomStatesForDepartmentAsync(departmentId.Value); + // Run all department-level lookups in parallel — they are independent of each other. + var departmentTask = _departmentsService.GetDepartmentByIdAsync(departmentId.Value); + var dispatchNumbersTask = _departmentSettingsService.GetTextToCallSourceNumbersForDepartmentAsync(departmentId.Value); + var authorizedTask = _limitsService.CanDepartmentProvisionNumberAsync(departmentId.Value); + var customStatesTask = _customStateService.GetAllActiveCustomStatesForDepartmentAsync(departmentId.Value); + + await System.Threading.Tasks.Task.WhenAll(departmentTask, dispatchNumbersTask, authorizedTask, customStatesTask); + + var department = departmentTask.Result; + var dispatchNumbers = dispatchNumbersTask.Result; + var authroized = authorizedTask.Result; + var customStates = customStatesTask.Result; messageEvent.CustomerId = departmentId.Value.ToString(); @@ -196,7 +202,9 @@ public async Task IncomingMessage([FromQuery] TwilioMessage reques if (!isDispatchSource) { - var profile = await _userProfileService.GetProfileByMobileNumberAsync(textMessage.Msisdn); + // Reuse the profile fetched above when the department was resolved via mobile number; + // only hit the DB again if the department came from the phone-number lookup path. + var profile = userProfile ?? await _userProfileService.GetProfileByMobileNumberAsync(textMessage.Msisdn); if (profile != null) {