Skip to content

Conversation

arturwolny-frontegg
Copy link
Contributor

No description provided.

arturwolny-frontegg and others added 14 commits July 31, 2023 10:58
…e manager implementations

BREAKING CHANGE: removed accessTokenOptions from FronteggContext configuration
test(context): fixed tests of FronteggContext
refactor(cache): decoupled cache managers from AccessTokens
# [6.0.0-alpha.1](5.1.1-alpha.1...6.0.0-alpha.1) (2023-07-31)

### Code Refactoring

* **sdk:** removed irrelevant accessTokenOptions; refactored cache manager implementations ([3bbe939](3bbe939))

### Bug Fixes

* **cache:** Bringing back the ICacheManager generic to the class level ([7d04440](7d04440))

### Features

* **cache:** decoupled cache managers from AccessTokens ([85db523](85db523))

### BREAKING CHANGES

* **sdk:** removed accessTokenOptions from FronteggContext configuration
@arturwolny-frontegg arturwolny-frontegg force-pushed the FR-12682-redis-entitlements-cache branch from df5dcfc to 83be07d Compare August 1, 2023 09:02
@arturwolny-frontegg arturwolny-frontegg marked this pull request as ready for review August 14, 2023 09:25
@arturwolny-frontegg arturwolny-frontegg force-pushed the FR-12682-redis-entitlements-cache branch from 6e12d8e to 7a0548e Compare August 16, 2023 12:28
@arturwolny-frontegg arturwolny-frontegg force-pushed the FR-12682-redis-entitlements-cache branch from 7a0548e to 5c3bbf3 Compare August 16, 2023 12:35

constructor(private readonly cache: ICacheManager<CacheValue>) {}

async loadSnapshotAsCurrent(dto: VendorEntitlementsDto): Promise<IsUpdatedToRev> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"loadSnapshotAsCurrent" - what is that "Current"? the name is not fully clear to me
maybe "loadSnapshotAsCurrentRevision" would be more explanatory

Copy link
Contributor Author

@arturwolny-frontegg arturwolny-frontegg Aug 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had these concerns as well, I found it very difficult to come up with self-explanatory and fancy names for methods. Seems like I failed in both aspects 😮‍💨


const cacheInitializer = new FronteggEntitlementsCacheInitializer(entitlementsCache);

const sources = new DtoToCacheSourcesMapper().map(dto);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not creating the mapper with static map function?

import IORedis from 'ioredis';
import { CacheValue } from '../cache.manager.interface';

// TODO: define all tests of Redis-based ICacheManager implementations in single file, only change the implementation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still need that todo?

Copy link
Contributor Author

@arturwolny-frontegg arturwolny-frontegg Aug 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it's about having a single .spec file for all ICacheManager instances, as they're about to do the same from the interface perspective

}
}

forScope<S extends CacheValue>(prefix?: string): ICacheManager<S> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this function be static?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, no. The intention was to create the new (scoped) instance of the same class, using the very same Redis connection (or NodeCache instance in case of local), but with different prefix and (important) - different typing.

When you use FronteggCache.getInstance() static method, in return you're receiving the instance and you don't really know (or - don't really NEED TO KNOW) what class it is. It's just fulfilling the ICacheManager interface. If this method is static, you'd need to iterate over known implementation and check which instance it is - and that's an antipattern, because in your code you need to know about the ICacheManager, not about particular implementations.

Usage of non-static method allows to apply the polymorphism here, so cache implementations know how to actually produce their scoped copies and don' leak implementation details that other parts of code should not be concerned about.

import { ICacheValueSerializer } from '../../serializers/types';
import { CacheValue, ICacheManagerCollection } from '../cache.manager.interface';

export class RedisCacheCollection implements ICacheManagerCollection<CacheValue> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the difference between this and the IORedis one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it uses different Redis library!

this.options.expireInMs,
);

this.scheduleLeadershipTry();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not calling this as part of becomeFollower function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The becomeFollower method should be called when the follower/leader status flips. When instance was a follower and still remains a follower, this method should not be called.

Why? I don't want to emit follower event after each leadership race that is lost.

private static EXTEND_LEADERSHIP_SCRIPT =
"if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) else return 0 end";

async tryToMaintainTheLock(key: string, value: string, expirationTimeMs: number): Promise<boolean> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add here a comment explaining how this works?

Logger.debug(`trying again in ${delayTime} seconds`);
await delay(delayTime * 1000);
return retry(func, { numberOfTries: numberOfTries - 1, secondsDelayRange });
const delayTime = Math.floor(Math.random() * (delayRangeMs.max - delayRangeMs.min + 1)) + delayRangeMs.min;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cycode: SAST violation: 'Use of a Broken or Risky Cryptographic Algorithm'.

crypto.pseudoRandomBytes()/Math.random() is a cryptographically weak random number generator.

Severity: Medium

Would you like to exclude this SAST violation from your status checks?
Tell us what to do with one of the following hashtags:

Tag Short Description
#cycode_sast_ignore_here Applies to this request only
#cycode_sast_false_positive Applies to this SAST violation for all repos in your organization

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants