@@ -30,8 +30,15 @@ export function consistentHashingChoice(
3030 return hr . get ( hash_string ( resource ) ) ;
3131}
3232
33+ // the subject that is used for the sticky router service
3334const 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.
3542
3643export function stickyKey ( { pattern, subject } ) {
3744 return pattern + " " + subject ;
@@ -60,7 +67,24 @@ export function getStickyTarget({
6067 return undefined ;
6168}
6269
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+ } ) {
6488 const sub = await client . subscribe ( SUBJECT ) ;
6589 const stickyCache : { [ key : string ] : { target : string ; expire : number } } = { } ;
6690
@@ -76,9 +100,9 @@ export async function createStickyRouter({ client }: { client: Client }) {
76100 if ( target == null || ! targets . includes ( target ) ) {
77101 // make a new choice
78102 target = consistentHashingChoice ( targets , subject ) ;
79- stickyCache [ key ] = { target, expire : Date . now ( ) + DEFAULT_TTL } ;
103+ stickyCache [ key ] = { target, expire : Date . now ( ) + choiceTtl } ;
80104 }
81- await mesg . respond ( { target, ttl : DEFAULT_TTL } ) ;
105+ await mesg . respond ( { target, ttl : clientTtl } ) ;
82106 } catch ( err ) {
83107 logger . debug ( "WARNING: unable to handle routing message" , err ) ;
84108 }
@@ -143,7 +167,7 @@ export async function stickyChoice({
143167 subject,
144168 targets : Array . from ( targets ) ,
145169 } ) ;
146- const { target, ttl = DEFAULT_TTL } = resp . data ;
170+ const { target, ttl = DEFAULT_CLIENT_TTL } = resp . data ;
147171 updateSticky ( { pattern, subject, target, ttl } ) ;
148172 return target ;
149173 }
0 commit comments