@@ -36,11 +36,19 @@ import { FallbackSampler } from './fallback-sampler';
3636import {
3737 AWSXRayRemoteSamplerConfig ,
3838 GetSamplingRulesResponse ,
39+ GetSamplingTargetsBody ,
40+ GetSamplingTargetsResponse ,
3941 SamplingRuleRecord ,
42+ SamplingTargetDocument ,
43+ TargetMap ,
4044} from './types' ;
41- import { RuleCache } from './rule-cache' ;
45+ import {
46+ DEFAULT_TARGET_POLLING_INTERVAL_SECONDS ,
47+ RuleCache ,
48+ } from './rule-cache' ;
4249
4350import { SamplingRuleApplier } from './sampling-rule-applier' ;
51+ import { PACKAGE_NAME } from './version' ;
4452
4553// 5 minute default sampling rules polling interval
4654const DEFAULT_RULES_POLLING_INTERVAL_SECONDS : number = 5 * 60 ;
@@ -94,17 +102,22 @@ export class AWSXRayRemoteSampler implements Sampler {
94102// Not intended for external use, use Parent-based `AWSXRayRemoteSampler` instead.
95103export class _AWSXRayRemoteSampler implements Sampler {
96104 private rulePollingIntervalMillis : number ;
105+ private targetPollingInterval : number ;
97106 private awsProxyEndpoint : string ;
98107 private ruleCache : RuleCache ;
99108 private fallbackSampler : FallbackSampler ;
100109 private samplerDiag : DiagLogger ;
101110 private rulePoller : NodeJS . Timeout | undefined ;
111+ private targetPoller : NodeJS . Timeout | undefined ;
102112 private clientId : string ;
103113 private rulePollingJitterMillis : number ;
114+ private targetPollingJitterMillis : number ;
104115 private samplingClient : AWSXRaySamplingClient ;
105116
106117 constructor ( samplerConfig : AWSXRayRemoteSamplerConfig ) {
107- this . samplerDiag = diag ;
118+ this . samplerDiag = diag . createComponentLogger ( {
119+ namespace : PACKAGE_NAME ,
120+ } ) ;
108121
109122 if (
110123 samplerConfig . pollingInterval == null ||
@@ -120,6 +133,8 @@ export class _AWSXRayRemoteSampler implements Sampler {
120133 }
121134
122135 this . rulePollingJitterMillis = Math . random ( ) * 5 * 1000 ;
136+ this . targetPollingInterval = this . getDefaultTargetPollingInterval ( ) ;
137+ this . targetPollingJitterMillis = ( Math . random ( ) / 10 ) * 1000 ;
123138
124139 this . awsProxyEndpoint = samplerConfig . endpoint
125140 ? samplerConfig . endpoint
@@ -137,7 +152,12 @@ export class _AWSXRayRemoteSampler implements Sampler {
137152 // Start the Sampling Rules poller
138153 this . startSamplingRulesPoller ( ) ;
139154
140- // TODO: Start the Sampling Targets poller
155+ // Start the Sampling Targets poller where the first poll occurs after the default interval
156+ this . startSamplingTargetsPoller ( ) ;
157+ }
158+
159+ public getDefaultTargetPollingInterval ( ) : number {
160+ return DEFAULT_TARGET_POLLING_INTERVAL_SECONDS ;
141161 }
142162
143163 public shouldSample (
@@ -203,6 +223,7 @@ export class _AWSXRayRemoteSampler implements Sampler {
203223
204224 public stopPollers ( ) {
205225 clearInterval ( this . rulePoller ) ;
226+ clearInterval ( this . targetPoller ) ;
206227 }
207228
208229 private startSamplingRulesPoller ( ) : void {
@@ -216,6 +237,27 @@ export class _AWSXRayRemoteSampler implements Sampler {
216237 this . rulePoller . unref ( ) ;
217238 }
218239
240+ private startSamplingTargetsPoller ( ) : void {
241+ // Update sampling targets every targetPollingInterval (usually 10 seconds)
242+ this . targetPoller = setInterval (
243+ ( ) => this . getAndUpdateSamplingTargets ( ) ,
244+ this . targetPollingInterval * 1000 + this . targetPollingJitterMillis
245+ ) ;
246+ this . targetPoller . unref ( ) ;
247+ }
248+
249+ private getAndUpdateSamplingTargets ( ) : void {
250+ const requestBody : GetSamplingTargetsBody = {
251+ SamplingStatisticsDocuments :
252+ this . ruleCache . createSamplingStatisticsDocuments ( this . clientId ) ,
253+ } ;
254+
255+ this . samplingClient . fetchSamplingTargets (
256+ requestBody ,
257+ this . updateSamplingTargets . bind ( this )
258+ ) ;
259+ }
260+
219261 private getAndUpdateSamplingRules ( ) : void {
220262 this . samplingClient . fetchSamplingRules ( this . updateSamplingRules . bind ( this ) ) ;
221263 }
@@ -242,6 +284,41 @@ export class _AWSXRayRemoteSampler implements Sampler {
242284 }
243285 }
244286
287+ private updateSamplingTargets (
288+ responseObject : GetSamplingTargetsResponse
289+ ) : void {
290+ try {
291+ const targetDocuments : TargetMap = { } ;
292+
293+ // Create Target-Name-to-Target-Map from sampling targets response
294+ responseObject . SamplingTargetDocuments . forEach (
295+ ( newTarget : SamplingTargetDocument ) => {
296+ targetDocuments [ newTarget . RuleName ] = newTarget ;
297+ }
298+ ) ;
299+
300+ // Update targets in the cache
301+ const [ refreshSamplingRules , nextPollingInterval ] : [ boolean , number ] =
302+ this . ruleCache . updateTargets (
303+ targetDocuments ,
304+ responseObject . LastRuleModification
305+ ) ;
306+ this . targetPollingInterval = nextPollingInterval ;
307+ clearInterval ( this . targetPoller ) ;
308+ this . startSamplingTargetsPoller ( ) ;
309+
310+ if ( refreshSamplingRules ) {
311+ this . samplerDiag . debug (
312+ 'Performing out-of-band sampling rule polling to fetch updated rules.'
313+ ) ;
314+ clearInterval ( this . rulePoller ) ;
315+ this . startSamplingRulesPoller ( ) ;
316+ }
317+ } catch ( error : unknown ) {
318+ this . samplerDiag . debug ( 'Error occurred when updating Sampling Targets' ) ;
319+ }
320+ }
321+
245322 private static generateClientId ( ) : string {
246323 const hexChars : string [ ] = [
247324 '0' ,
0 commit comments