@@ -30,8 +30,15 @@ export function consistentHashingChoice(
30
30
return hr . get ( hash_string ( resource ) ) ;
31
31
}
32
32
33
+ // the subject that is used for the sticky router service
33
34
const SUBJECT = "sticky.one" ;
34
- const DEFAULT_TTL = 15_000 ;
35
+
36
+ const DEFAULT_CHOICE_TTL = 60_000 * 60 * 24 * 30 ; // 30 days
37
+
38
+ const DEFAULT_CLIENT_TTL = 15_000 ; // 15 seconds
39
+
40
+ // NOTE: there are no assumptions here about clocks being synchronized. These
41
+ // are just ttl's.
35
42
36
43
export function stickyKey ( { pattern, subject } ) {
37
44
return pattern + " " + subject ;
@@ -60,7 +67,24 @@ export function getStickyTarget({
60
67
return undefined ;
61
68
}
62
69
63
- export async function createStickyRouter ( { client } : { client : Client } ) {
70
+ export async function createStickyRouter ( {
71
+ client,
72
+ // when the stick router service makes a choice, it keeps it this
73
+ // long, or until the choice it made is no longer valid (i.e., the target
74
+ // vanishes). This may as well be infinite, but it is nice to have the
75
+ // option to discard choices from memory to avoid leaks.
76
+ choiceTtl = DEFAULT_CHOICE_TTL ,
77
+ // The client trusts a choice returned from the router for this long,
78
+ // or until the target is no longer available. Thus if the target
79
+ // is randomly vanishing and coming back and a reassignment gets made,
80
+ // this client would definitely find out if necessary within this amount of time.
81
+ // Basically this is roughly how long failover may take.
82
+ clientTtl = DEFAULT_CLIENT_TTL ,
83
+ } : {
84
+ client : Client ;
85
+ choiceTtl ?: number ;
86
+ clientTtl ?: number ;
87
+ } ) {
64
88
const sub = await client . subscribe ( SUBJECT ) ;
65
89
const stickyCache : { [ key : string ] : { target : string ; expire : number } } = { } ;
66
90
@@ -76,9 +100,9 @@ export async function createStickyRouter({ client }: { client: Client }) {
76
100
if ( target == null || ! targets . includes ( target ) ) {
77
101
// make a new choice
78
102
target = consistentHashingChoice ( targets , subject ) ;
79
- stickyCache [ key ] = { target, expire : Date . now ( ) + DEFAULT_TTL } ;
103
+ stickyCache [ key ] = { target, expire : Date . now ( ) + choiceTtl } ;
80
104
}
81
- await mesg . respond ( { target, ttl : DEFAULT_TTL } ) ;
105
+ await mesg . respond ( { target, ttl : clientTtl } ) ;
82
106
} catch ( err ) {
83
107
logger . debug ( "WARNING: unable to handle routing message" , err ) ;
84
108
}
@@ -143,7 +167,7 @@ export async function stickyChoice({
143
167
subject,
144
168
targets : Array . from ( targets ) ,
145
169
} ) ;
146
- const { target, ttl = DEFAULT_TTL } = resp . data ;
170
+ const { target, ttl = DEFAULT_CLIENT_TTL } = resp . data ;
147
171
updateSticky ( { pattern, subject, target, ttl } ) ;
148
172
return target ;
149
173
}
0 commit comments