Change Document: v2.4.0.0 — Job Queue Batch Cap, Field Widening, and SecretText Migration
| Field | Value |
|---|---|
| Version | 2.4.0.0 |
| Date | 2026-03-11 |
| Extension | BC Dialing Application (Cambay Solutions) |
| Severity | High — resolves email backlog throughput issue and eliminates deprecation warnings |
| Status | Implemented — pending deployment |
Background
Three issues converged to motivate this version:
-
ISSUE-15 — Email backlog. Production telemetry showed 630+ pending email log records accumulating in the
CustomerEmailLogtable. The Job Queue codeunit (CU-60003) processes all pending records in a single run with no batch size limit. With each email log requiring 2 Nextiva API calls + 2 Azure Blob uploads, a 630-record run takes 30+ minutes — long enough to outlast the Nextiva auth token, causing cascading failures across all remaining records. Records that hit 3 failed attempts are permanently abandoned. -
Text field constraints. A recurring
"The length of the string is 21, but it must be less than or equal to 20 characters"error was blocking recording and transcript sync. Multiple tables hadText[20]fields that were too narrow for production data —AssetTypeon NextivaData,PhoneNumberon CustomerPhoneLog,EmailAddresson CustomerEmailLog, and error log fields on Nextiva Error Logs. -
UseReadySAS deprecation. Both CU-60003 and CU-60004 used the deprecated
UseReadySAS(Text)overload, generating AL0432 compiler warnings. This was listed as a v2.4.0.0 follow-up in the v2.3.0.0 CHANGE document.
Summary of Changes
| # | Severity | Category | Description |
|---|---|---|---|
| 1 | High | Added | Configurable batch cap for Job Queue processing — limits phone and email log records processed per run |
| 2 | High | Added | Immediate abandonment for permanent failures — "Customer Not found" errors skip retries |
| 3 | High | Fixed | Widened Text fields across 4 tables to prevent string length constraint errors |
| 4 | Medium | Fixed | Migrated UseReadySAS from deprecated Text to SecretText parameter type (AL0432 warning) |
| 5 | Medium | Fixed | Eliminated double Get() + Modify(true) on success path — attempt increment folded into flag update |
| 6 | Low | Changed | Job Queue startup telemetry (BCDIALER-1000) now uses Dictionary overload with batch cap values |
| 7 | Low | Added | Batch cap fields exposed on NextivaConfigAPI page for monitoring visibility |
| 8 | Low | Added | Upgrade codeunit populates batch cap defaults for pre-2.4.0.0 installs |
Detailed Changes
1. Job Queue Batch Cap (High)
Files: src/Table/Tab80003.NextivaConfig.al, src/Page/Pag-80007.NextivaSetupPage.al, src/Codeunit/CU60003.NextivaIntegration.al
Problem: CU-60003's OnRun trigger processes every pending phone and email log record in a single Job Queue run. With no upper bound, a backlog of 630 email logs means:
- 2,520+ HTTP round-trips per run (4 per phone log, 2 per email log)
- 30+ minute run duration
- Nextiva auth token likely expires mid-run, causing cascading failures
- All failed records increment their
Attemptscounter toward the 3-attempt abandonment threshold
Fix: Two new Integer fields on NextivaConfig:
"Max Phone Logs Per Run"(field 7, default 50, range 1–1000)"Max Email Logs Per Run"(field 8, default 50, range 1–1000)
Both processing loops in OnRun now check a BatchCount counter against the configured maximum. When the cap is reached, the loop exits with a BCDIALER-1002 telemetry message recording how many records were processed vs. errored, and the remaining records are deferred to the next Job Queue run.
The cap counts only actual processing attempts — records with empty NextivaSessionID are skipped without incrementing the counter.
Impact: With a 50-record batch cap and a 30-second Job Queue interval, a 630-record backlog clears in ~13 runs (~6.5 minutes) with predictable, bounded run duration per cycle.
2. Immediate Abandonment for Permanent Failures (High)
Files: src/Codeunit/CU60003.NextivaIntegration.al
Problem: When TryProcessPhoneLog or TryProcessEmailLog fails because no Customer matches the phone number or email address, the error is transient from the code's perspective — it increments Attempts and retries on the next run. But "Customer Not found" is a permanent condition: the Customer record won't appear between runs. Each retry burns one of three attempts and wastes an HTTP round-trip for the Customer lookup, contributing to backlog growth.
Fix: New AbandonRecord procedure sets Attempts := 3 immediately on the log record, removing it from the processing queue. The main loop checks GetLastErrorText() against a CustomerNotFoundTok label constant — if the error matches, AbandonRecord is called instead of UpdateAttempt. Abandoned records are logged as BCDIALER-5002 (Warning severity) with the SourceNo and SessionID.
The error text matching uses two named constants declared at the codeunit level:
CustomerNotFoundErr: Label 'Customer Not found with %1'— used in theError()callCustomerNotFoundTok: Label 'Customer Not found with'— used in theContains()check
This eliminates the magic string duplication that would otherwise make the match fragile.
3. Text Field Widening (High)
Files: src/Table/Tab80001.NextivaData.al, src/Table/Tab80000.CustomerPhoneLog.al, src/Table/Tab80002.CustomerEmailLog.al, src/Table/Tab80004.NextivaErrorLogs.al
| Table | Field | Before | After | Rationale |
|---|---|---|---|---|
| NextivaData (80001) | AssetType | Text[20] | Text[100] | 21-char value triggered runtime error; generous sizing for unknown Nextiva payload values |
| CustomerPhoneLog (80000) | PhoneNumber | Text[20] | Text[50] | E.164 with extensions can exceed 20 chars |
| CustomerEmailLog (80002) | EmailAddress | Text[20] | Text[250] | Email addresses routinely exceed 20 chars; aligns with the existing EmailAddress1 Text[255] workaround field |
| Nextiva Error Logs (80004) | Source Type | Text[20] | Text[50] | Room for longer source type identifiers |
| Nextiva Error Logs (80004) | Error Title | Text[20] | Text[100] | Error titles were being truncated |
All changes are non-destructive column widenings — existing data is preserved, no reindex required.
4. SecretText Migration (Medium)
Files: src/Codeunit/CU60003.NextivaIntegration.al, src/Codeunit/CU-60004.NextivaIntegrationManual.al
Problem: Both codeunits used the deprecated UseReadySAS(Text) overload in TryInitializeAuth, generating AL0432 compiler warnings. The Text parameter type also meant the SAS token could appear in runtime logs.
Fix: Changed the CachedSASToken codeunit-level variable from Text to SecretText in both CU-60003 and CU-60004. The local SASToken variable in TryInitializeAuth is now SecretText. The hardcoded fallback token is assigned through an intermediate Text variable (FallbackToken) because AL does not allow implicit string literal → SecretText conversion. The UseReadySAS(SecretText) overload is now used, eliminating the deprecation warning.
Impact: Zero functional change. The SAS token is now protected from accidental exposure in runtime logs and telemetry.
5. Double Modify Elimination (Medium)
Files: src/Codeunit/CU60003.NextivaIntegration.al
Problem: On the success path, both UpdateAllPhoneLogFlags and UpdateAttempt performed separate Get() + Modify(true) calls on the same phone/email log record. Two database round-trips per successful record — 100 unnecessary DB operations per 50-record batch.
Fix: Folded the Attempts += 1 increment into UpdateAllPhoneLogFlags and UpdateAllEmailLogFlags. Removed the separate UpdateAttempt call from the success path in both processing loops. The failure path still calls UpdateAttempt or AbandonRecord separately (both do their own Get() + Modify(true)), which is acceptable since failures are infrequent.
6. Startup Telemetry Enhancement (Low)
Files: src/Codeunit/CU60003.NextivaIntegration.al
The BCDIALER-1000 startup telemetry message now includes MaxPhoneLogs and MaxEmailLogs dimensions alongside the existing PendingPhoneLogs and PendingEmailLogs counts. Uses the Dictionary of [Text, Text] overload instead of individual key-value pairs (which only supports 2 pairs).
7. Config API Page Update (Low)
Files: src/Page/Pag-80010.NextivaConfigAPI.al
Added maxPhoneLogsPerRun and maxEmailLogsPerRun fields to the read-only API page. Enables monitoring tools and integration tests to verify batch cap configuration without accessing the BC UI.
8. Upgrade Codeunit — Batch Cap Defaults (Low)
Files: src/Codeunit/CU-60005.DialerUpgrade.al
New PopulateBatchCapDefaults procedure runs for upgrades from versions below 2.4.0.0. Sets "Max Phone Logs Per Run" and "Max Email Logs Per Run" to 50 on the existing config record if the field value is 0 (pre-upgrade state). A Changed boolean guard prevents unnecessary Modify() calls when both fields are already populated.
Object Inventory
| Object ID | Object Type | Name | Status |
|---|---|---|---|
| 60003 | Codeunit | Nextiva Integration | Modified — batch cap, abandonment, SecretText, double Modify fix, telemetry |
| 60004 | Codeunit | Nextiva Integration Manual | Modified — SecretText migration |
| 60005 | Codeunit | Dialer Upgrade | Modified — batch cap defaults procedure |
| 80000 | Table | CustomerPhoneLog | Modified — PhoneNumber widened to Text[50] |
| 80001 | Table | NextivaData | Modified — AssetType widened to Text[100] |
| 80002 | Table | CustomerEmailLog | Modified — EmailAddress widened to Text[250] |
| 80003 | Table | NextivaConfig | Modified — two new Integer fields (Max Phone/Email Logs Per Run) |
| 80004 | Table | Nextiva Error Logs | Modified — Source Type widened to Text[50], Error Title widened to Text[100] |
| 80007 | Page | NextivaSetup | Modified — Job Queue Settings group with batch cap fields |
| 80010 | Page | NextivaConfigAPI | Modified — batch cap fields exposed |
| — | app.json | Extension manifest | Modified — version bump to 2.4.0.0 |
Known Limitations
Hardcoded Credential Fallbacks Still Present (Transitional)
The v2.3.0.0 CHANGE document recommended removing hardcoded fallbacks in v2.4.0.0. This was deferred to keep v2.4.0.0 focused on the batch cap and field widening fixes. The fallbacks continue to emit telemetry warnings (BCDIALER-0001 through BCDIALER-0003) when activated. Removal is planned for v2.5.0.0.
Azure Storage Account and Container Not Yet Externalized
Still hardcoded as p360data and nextiva-bc in CU-60003 and CU-60004. Deferred from v2.3.0.0, still deferred.
No Automated Tests
The extension has no AL test codeunits. The batch cap and abandonment logic would benefit from unit tests but are deferred pending extraction of business logic into testable helper codeunits.
Batch Cap Does Not Account for Empty-Session Records
The batch counter only increments for records with a non-empty NextivaSessionID. In a pathological case with many empty-session records interspersed among valid ones, the loop could scan more records than the configured maximum. Empty-session records should not exist in practice (API pages require a session ID), and the cap still enforces a hard limit on actual processing work.
Deployment Notes
Pre-Deployment
- No manual configuration required. The upgrade codeunit sets batch cap defaults automatically.
- No new dependencies.
- Schema changes (Text field widening, new Integer fields) are non-destructive and handled automatically by BC during upgrade.
Deployment
- Build the
.apppackage via AL: Package in VS Code - Deploy to the target environment via Extension Management or the admin center
- The upgrade codeunit runs automatically during installation
Post-Deployment Verification
-
Verify batch cap configuration via OData:
GET /api/CambaySolutions/PhoneIntegration/v1.0/nextivaConfigsConfirm
maxPhoneLogsPerRun = 50andmaxEmailLogsPerRun = 50. -
Verify via Nextiva Config Setup page (80007): New "Job Queue Settings" group should show both batch cap fields with value 50.
-
Monitor Application Insights for the first hour:
BCDIALER-1000events should showMaxPhoneLogs=50andMaxEmailLogs=50in custom dimensionsBCDIALER-1002events indicate the batch cap was reached — expected during backlog drainBCDIALER-5002events indicate permanent failure abandonment — review these to identify missing Customer records- No AL0432 compiler warnings in the build output
-
Monitor backlog drain: With a 50-record cap and 30-second Job Queue interval, the 630-record email backlog should clear within ~15 minutes. Track via
BCDIALER-1000pending counts decreasing over successive runs.
Testing
Key scenarios for this version:
| # | Scenario | Expected Result |
|---|---|---|
| 1 | Job Queue with > 50 pending phone logs | Processes exactly 50, logs BCDIALER-1002, remaining deferred to next run |
| 2 | Job Queue with > 50 pending email logs | Same as above for emails |
| 3 | Job Queue with < 50 pending records | Processes all, no BCDIALER-1002 event |
| 4 | Phone log with no matching Customer | Record immediately abandoned (Attempts set to 3), BCDIALER-5002 logged, no retry on next run |
| 5 | Email log with no matching Customer | Same as above for emails |
| 6 | Transient failure (Nextiva API timeout) | Attempts incremented by 1, record retried on next run (up to 3 attempts) |
| 7 | AssetType value > 20 characters | No error — field now Text[100] |
| 8 | Phone number > 20 characters | No error — field now Text[50] |
| 9 | Email address > 20 characters | No error — field now Text[250] |
| 10 | Batch cap fields visible on Config Setup page | "Job Queue Settings" group shows both fields with default 50 |
| 11 | Batch cap fields visible on Config API | OData response includes maxPhoneLogsPerRun and maxEmailLogsPerRun |
| 12 | Azure Blob upload uses SecretText SAS token | No AL0432 deprecation warnings; blob uploads succeed as before |
| 13 | Upgrade from 2.3.6.0 | Batch cap fields auto-populated to 50; existing config values preserved |