Skip to content

Commit 85f0542

Browse files
authored
fix: clear instance cache for init with fresh credentials (#106)
1 parent df56cfa commit 85f0542

File tree

3 files changed

+23
-5
lines changed

3 files changed

+23
-5
lines changed

lib/impl/CosmosStateStore.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,13 @@ class CosmosStateStore extends StateStore {
7373
* @override
7474
* @private
7575
*/
76-
constructor (container, partitionKey) {
76+
constructor (container, partitionKey, /* istanbul ignore next */ options = { expiration: null }) {
7777
super()
7878
/** @private */
7979
this._cosmos = {}
8080
this._cosmos.container = container
8181
this._cosmos.partitionKey = partitionKey
82+
this.expiration = options.expiration
8283
}
8384

8485
/**
@@ -102,7 +103,7 @@ class CosmosStateStore extends StateStore {
102103
containerId: joi.string().required(),
103104
partitionKey: joi.string().required(),
104105

105-
expiration: joi.string() // allowed for tvm response
106+
expiration: joi.string() // allowed for tvm response, in ISO format
106107
}).xor('masterKey', 'resourceToken').required()
107108
.validate(credentials)
108109
if (validation.error) {
@@ -112,9 +113,16 @@ class CosmosStateStore extends StateStore {
112113
}))
113114
}
114115

116+
const inMemoryInstance = CosmosStateStore.inMemoryInstance[credentials.partitionKey]
117+
if (inMemoryInstance && inMemoryInstance.expiration !== credentials.expiration) {
118+
// the TVM credentials have changed, aio-lib-core-tvm has generated new one likely because of expiration.
119+
delete CosmosStateStore.inMemoryInstance[credentials.partitionKey]
120+
}
121+
115122
if (!CosmosStateStore.inMemoryInstance[credentials.partitionKey]) {
116123
let cosmosClient
117124
if (credentials.resourceToken) {
125+
// Note: resourceToken doesn't necessarily mean that the TVM provided the credentials, it can have been provided by a user.
118126
logger.debug('using azure cosmos resource token')
119127
cosmosClient = new cosmos.CosmosClient({ endpoint: credentials.endpoint, consistencyLevel: 'Session', tokenProvider: /* istanbul ignore next */ async () => credentials.resourceToken })
120128
} else {
@@ -125,7 +133,7 @@ class CosmosStateStore extends StateStore {
125133
// container = (await database.containers.createIfNotExists({ id: credentials.containerId })).container
126134
}
127135
const container = cosmosClient.database(credentials.databaseId).container(credentials.containerId)
128-
CosmosStateStore.inMemoryInstance[credentials.partitionKey] = new CosmosStateStore(container, credentials.partitionKey)
136+
CosmosStateStore.inMemoryInstance[credentials.partitionKey] = new CosmosStateStore(container, credentials.partitionKey, { expiration: credentials.expiration })
129137
} else {
130138
logger.debug('reusing exising in-memory CosmosClient initialization')
131139
}

lib/init.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ async function wrapTVMRequest (promise, params) {
8888
* @returns {Promise<StateStore>} A StateStore instance
8989
*/
9090
async function init (config = {}) {
91-
// todo joi-validate config here or leave it to StateStore impl + TvmClient?
92-
9391
// 0. log
9492
const logConfig = utils.withHiddenFields(config, ['ow.auth', 'cosmos.resourceToken', 'cosmos.masterKey'])
9593

test/impl/CosmosStateStore.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ describe('init', () => {
181181
expect(cosmos.CosmosClient).toHaveBeenCalledTimes(0)
182182
})
183183
test('successive calls should reuse the CosmosStateStore instance - with masterkey', async () => {
184+
// note this test may be confusing as no reuse is made with BYO credentials, but the cache is actually deleted by the top level init file. See test below.
184185
await testInitOK(fakeCosmosMasterCredentials)
185186
expect(cosmos.CosmosClient).toHaveBeenCalledTimes(1)
186187
cosmos.CosmosClient.mockReset()
@@ -194,6 +195,17 @@ describe('init', () => {
194195
// New CosmosClient instance generated again
195196
expect(cosmos.CosmosClient).toHaveBeenCalledTimes(2)
196197
})
198+
test('No reuse if TVM credential expiration changed', async () => {
199+
await testInitOK(fakeCosmosTVMResponse)
200+
expect(cosmos.CosmosClient).toHaveBeenCalledTimes(1)
201+
await CosmosStateStore.init({ ...fakeCosmosTVMResponse, expiration: new Date(0).toISOString() })
202+
expect(cosmos.CosmosClient).toHaveBeenCalledTimes(2)
203+
await CosmosStateStore.init({ ...fakeCosmosTVMResponse, expiration: new Date(1).toISOString() })
204+
expect(cosmos.CosmosClient).toHaveBeenCalledTimes(3)
205+
// double check, same credentials no additional call
206+
await CosmosStateStore.init({ ...fakeCosmosTVMResponse, expiration: new Date(1).toISOString() })
207+
expect(cosmos.CosmosClient).toHaveBeenCalledTimes(3)
208+
})
197209
})
198210
})
199211
})

0 commit comments

Comments
 (0)