Intelligent routing and strategy management system for credit bureau services. Dynamically selects bureau providers based on configurable strategies including date ranges, load distribution, failover, and dual bureau calls.
The router provides centralized control over bureau selection without changing application code. Strategies can be adjusted in real-time through the def_bureau_strategy table to:
The router acts as a facade, instantiating and calling the appropriate bureau implementation(s) based on strategy rules.
Application → ObjServiceBureauRouter → [Strategy Selection]
↓
[Primary Bureau]
[Failover Bureau] (if primary fails)
[Dual Bureau] (simultaneously)
The def_bureau_strategy table controls routing decisions:
CREATE TABLE IF NOT EXISTS `def_bureau_strategy` (
`BureauCode` char(50) DEFAULT NULL, -- Primary bureau (e.g., "EXPERIAN")
`StartDate` date DEFAULT NULL, -- Strategy start date (NULL = immediate)
`EndDate` date DEFAULT NULL, -- Strategy end date (NULL = indefinite)
`RDG_Start` int(11) DEFAULT NULL, -- Load distribution start (0-100)
`RDG_End` int(11) DEFAULT NULL, -- Load distribution end (0-100)
`FailoverBureau` char(50) DEFAULT NULL, -- Backup bureau on failure
`DualBureau` char(50) DEFAULT NULL, -- Call both simultaneously
`Default` char(1) DEFAULT NULL -- Mark as default ('Y'/'1') for fallback
) ENGINE=InnoDB
Strategies are active only if current date is within range:
This enables:
RDG (Random Distribution Group) uses persistent random values 0-100 to split traffic. Each ID number is assigned a permanent RDG value that determines routing consistently.
Key Feature: Persistent Routing
data_rdg_idnumber tableExample: 70/30 split between two bureaus:
INSERT INTO def_bureau_strategy VALUES ('EXPERIAN', NULL, NULL, 0, 70, NULL, NULL, 'N');
INSERT INTO def_bureau_strategy VALUES ('MYDATA', NULL, NULL, 71, 100, NULL, NULL, 'N');
Selection Process:
data_rdg_idnumber)RDG_Start <= rdg_value <= RDG_EndExample Flow:
ID 8901015800082:
First call → RDG1=45 assigned → Routes to EXPERIAN (45 in range 0-70)
Second call → RDG1=45 (same) → Routes to EXPERIAN (always)
Third call → RDG1=45 (same) → Routes to EXPERIAN (always)
ID 9001015800083:
First call → RDG1=78 assigned → Routes to MYDATA (78 in range 71-100)
Second call → RDG1=78 (same) → Routes to MYDATA (always)
Benefits:
If FailoverBureau is configured and primary bureau fails:
Example: Use MyData if Experian fails:
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 100, 'MYDATA', NULL);
If DualBureau is configured, call both bureaus regardless of primary success:
Use Cases:
Example: Call both Experian and MyData:
INSERT INTO def_bureau_strategy
VALUES ('EXPERIAN', NULL, NULL, 0, 100, NULL, 'MYDATA', NULL);
The Default column marks a bureau as the fallback option when no active strategies match:
Trigger Conditions:
Configuration: Set Default to 'Y' or '1':
INSERT INTO def_bureau_strategy (BureauCode, `Default`)
VALUES ('EXPERIAN', 'Y');
Behavior:
Use Cases:
Important Notes:
Example: Ensure Experian is always available as fallback:
INSERT INTO def_bureau_strategy (BureauCode, `Default`)
VALUES ('EXPERIAN', 'Y');
get_active_strategies() - Query all currently active strategies from table, filtered by date rangeget_default_bureau() - Query bureau marked as Default='Y' or '1' for fallbackget_id_number_from_guid(guid) - Lookup ID number from GUID in bloom_hcscore tableselect_bureau_by_rdg(strategies, id_number) - Select bureau based on persistent RDG value
data_rdg_idnumber tableinstantiate_bureau(bureau_code, DB) - Create bureau instance from registry, copying request parameters (Guid, Param1-3)call_bureau(bureau_code, guid) - Instantiate and call specific bureaucall_dual_bureau(primary_code, dual_code, guid) - Call two bureaus simultaneouslycall_with_failover(primary_code, failover_code, guid) - Call with automatic failoverresolve(guid, id_number) - Execute complete routing logic:
1. def_random - RDG configuration table
CREATE TABLE IF NOT EXISTS def_random (
Package VARCHAR(50) NOT NULL,
RDCode VARCHAR(50) NOT NULL,
PrimaryGuid VARCHAR(50) NOT NULL,
RDGFields INT DEFAULT 1,
Description TEXT,
Active CHAR(1) DEFAULT 'Y',
Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
Updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (Package, RDCode)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2. Configuration record for bureau routing:
INSERT INTO def_random (Package, RDCode, PrimaryGuid, RDGFields, Description, Active)
VALUES ('homechoice', 'BUREAU_ROUTING', 'idnumber', 1, 'Bureau routing with persistent RDG', 'Y');
3. data_rdg_idnumber - RDG storage table (created automatically)
The router automatically creates this table on first use via ObjRandom:
CREATE TABLE IF NOT EXISTS data_rdg_idnumber (
idnumber VARCHAR(255) NOT NULL,
RDG1 INT DEFAULT NULL,
Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
Updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (idnumber)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Or manually create:
python factory.core/ObjRandom.py create-rdg BUREAU_ROUTING
First Request for ID 8901015800082:
select_bureau_by_rdg(strategies, '8901015800082')data_rdg_idnumber - not foundINSERT INTO data_rdg_idnumber (idnumber, RDG1) VALUES ('8901015800082', 45);
All Future Requests for ID 8901015800082:
select_bureau_by_rdg(strategies, '8901015800082')data_rdg_idnumber - found with RDG1=45Result: Same ID always routes to same bureau!
100% traffic to single bureau:
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End)
VALUES ('EXPERIAN', 0, 100);
Start with 20% to new bureau, 80% to old:
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End)
VALUES ('MYDATA', 0, 20);
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End)
VALUES ('EXPERIAN', 21, 100);
Later increase to 50/50, then 100% to new bureau.
Switch from old to new bureau on specific date:
-- Old bureau until migration date
INSERT INTO def_bureau_strategy (BureauCode, StartDate, EndDate, RDG_Start, RDG_End)
VALUES ('EXPERIAN', '2026-01-01', '2026-06-30', 0, 100);
-- New bureau from migration date
INSERT INTO def_bureau_strategy (BureauCode, StartDate, RDG_Start, RDG_End)
VALUES ('MYDATA', '2026-07-01', 0, 100);
Primary with automatic failover:
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End, FailoverBureau)
VALUES ('EXPERIAN', 0, 100, 'MYDATA');
Call both bureaus for every request:
INSERT INTO def_bureau_strategy (BureauCode, RDG_Start, RDG_End, DualBureau)
VALUES ('EXPERIAN', 0, 100, 'MYDATA');
Set up active strategies with a default fallback:
-- Active strategy for production (July-December 2026)
INSERT INTO def_bureau_strategy (BureauCode, StartDate, EndDate, RDG_Start, RDG_End)
VALUES ('MYDATA', '2026-07-01', '2026-12-31', 0, 100);
-- Default fallback (always available when no active strategy matches)
INSERT INTO def_bureau_strategy (BureauCode, `Default`)
VALUES ('EXPERIAN', 'Y');
In this example:
# Execute bureau routing for specific GUID
python ObjServiceBureauRouter.py {guid}
# List registered bureaus
python ObjServiceBureauRouter.py list
Before using the router, ensure all bureau implementations are registered:
# In ObjServiceHCMyData.py
ObjServiceBureau.register_bureau("MYDATA", ObjServiceApi)
# In ObjServiceHCExperian.py (future update)
ObjServiceBureau.register_bureau("EXPERIAN", ObjServiceApi)
Registration happens at module import time.
Set DO_DEBUG = True at module level to enable detailed logging:
ObjServiceBureau.py - Base bureau framework classObjServiceHCExperian.py - Experian implementationObjServiceHCMyData.py - MyData implementationAxion 8.x