diff --git a/packages/client-sdk-nodejs/src/config/configuration.ts b/packages/client-sdk-nodejs/src/config/configuration.ts index 7813899ba..f0cdaad56 100644 --- a/packages/client-sdk-nodejs/src/config/configuration.ts +++ b/packages/client-sdk-nodejs/src/config/configuration.ts @@ -1,7 +1,7 @@ import {RetryStrategy} from './retry/retry-strategy'; import {Middleware} from './middleware/middleware'; import {MomentoLoggerFactory} from '../'; -import {TransportStrategy} from '../config/transport/transport-strategy'; +import {TransportStrategy} from './transport'; export interface ConfigurationProps { /** diff --git a/packages/client-sdk-nodejs/src/config/configurations.ts b/packages/client-sdk-nodejs/src/config/configurations.ts index 3df315b9b..c99627b09 100644 --- a/packages/client-sdk-nodejs/src/config/configurations.ts +++ b/packages/client-sdk-nodejs/src/config/configurations.ts @@ -11,7 +11,7 @@ import { StaticGrpcConfiguration, StaticTransportStrategy, TransportStrategy, -} from '../config/transport'; +} from './transport'; // 4 minutes. We want to remain comfortably underneath the idle timeout for AWS NLB, which is 350s. const defaultMaxIdleMillis = 4 * 60 * 1_000; diff --git a/packages/client-sdk-nodejs/src/config/transport/index.ts b/packages/client-sdk-nodejs/src/config/transport/index.ts index 72e3e8fad..274180861 100644 --- a/packages/client-sdk-nodejs/src/config/transport/index.ts +++ b/packages/client-sdk-nodejs/src/config/transport/index.ts @@ -1 +1,2 @@ -export * from '@gomomento/sdk-core/dist/src/config/transport'; +export * from './grpc-configuration'; +export * from './transport-strategy'; diff --git a/packages/client-sdk-nodejs/src/config/transport/transport-strategy.ts b/packages/client-sdk-nodejs/src/config/transport/transport-strategy.ts index 4f103b195..290acd344 100644 --- a/packages/client-sdk-nodejs/src/config/transport/transport-strategy.ts +++ b/packages/client-sdk-nodejs/src/config/transport/transport-strategy.ts @@ -1 +1,129 @@ -export * from '@gomomento/sdk-core/dist/src/config/transport/transport-strategy'; +import {GrpcConfiguration, GrpcConfigurationProps} from './grpc-configuration'; + +export interface TransportStrategy { + /** + * Configures the low-level gRPC settings for the Momento client's communication + * with the Momento server. + * @returns {GrpcConfiguration} + */ + getGrpcConfig(): GrpcConfiguration; + + /** + * Copy constructor for overriding the gRPC configuration + * @param {GrpcConfiguration} grpcConfig + * @returns {TransportStrategy} a new TransportStrategy with the specified gRPC config. + */ + withGrpcConfig(grpcConfig: GrpcConfiguration): TransportStrategy; + + /** + * Copy constructor to update the client-side timeout + * @param {number} clientTimeoutMillis + * @returns {TransportStrategy} a new TransportStrategy with the specified client timeout + */ + withClientTimeoutMillis(clientTimeoutMillis: number): TransportStrategy; + + /** + * The maximum duration for which a connection may remain idle before being replaced. This + * setting can be used to force re-connection of a client if it has been idle for too long. + * In environments such as AWS lambda, if the lambda is suspended for too long the connection + * may be closed by the load balancer, resulting in an error on the subsequent request. If + * this setting is set to a duration less than the load balancer timeout, we can ensure that + * the connection will be refreshed to avoid errors. + * @returns {number} + */ + getMaxIdleMillis(): number; + + /** + * Copy constructor to update the max idle connection timeout. (See {getMaxIdleMillis}.) + * @param {number} maxIdleMillis + * @returns {TransportStrategy} a new TransportStrategy with the specified max idle connection timeout. + */ + withMaxIdleMillis(maxIdleMillis: number): TransportStrategy; +} + +export interface TransportStrategyProps { + /** + * low-level gRPC settings for communication with the Momento server + */ + grpcConfiguration: GrpcConfiguration; + /** + * The maximum duration for which a connection may remain idle before being replaced. This + * setting can be used to force re-connection of a client if it has been idle for too long. + * In environments such as AWS lambda, if the lambda is suspended for too long the connection + * may be closed by the load balancer, resulting in an error on the subsequent request. If + * this setting is set to a duration less than the load balancer timeout, we can ensure that + * the connection will be refreshed to avoid errors. + * @returns {number} + */ + maxIdleMillis: number; +} + +export class StaticGrpcConfiguration implements GrpcConfiguration { + private readonly deadlineMillis: number; + private readonly maxSessionMemoryMb: number; + constructor(props: GrpcConfigurationProps) { + this.deadlineMillis = props.deadlineMillis; + this.maxSessionMemoryMb = props.maxSessionMemoryMb; + } + + getDeadlineMillis(): number { + return this.deadlineMillis; + } + + getMaxSessionMemoryMb(): number { + return this.maxSessionMemoryMb; + } + + withDeadlineMillis(deadlineMillis: number): StaticGrpcConfiguration { + return new StaticGrpcConfiguration({ + deadlineMillis: deadlineMillis, + maxSessionMemoryMb: this.maxSessionMemoryMb, + }); + } + + withMaxSessionMemoryMb(maxSessionMemoryMb: number): StaticGrpcConfiguration { + return new StaticGrpcConfiguration({ + deadlineMillis: this.deadlineMillis, + maxSessionMemoryMb: maxSessionMemoryMb, + }); + } +} + +export class StaticTransportStrategy implements TransportStrategy { + private readonly grpcConfig: GrpcConfiguration; + private readonly maxIdleMillis: number; + + constructor(props: TransportStrategyProps) { + this.grpcConfig = props.grpcConfiguration; + this.maxIdleMillis = props.maxIdleMillis; + } + + getGrpcConfig(): GrpcConfiguration { + return this.grpcConfig; + } + + withGrpcConfig(grpcConfig: GrpcConfiguration): StaticTransportStrategy { + return new StaticTransportStrategy({ + grpcConfiguration: grpcConfig, + maxIdleMillis: this.maxIdleMillis, + }); + } + + getMaxIdleMillis(): number { + return this.maxIdleMillis; + } + + withMaxIdleMillis(maxIdleMillis: number): TransportStrategy { + return new StaticTransportStrategy({ + grpcConfiguration: this.grpcConfig, + maxIdleMillis: maxIdleMillis, + }); + } + + withClientTimeoutMillis(clientTimeout: number): StaticTransportStrategy { + return new StaticTransportStrategy({ + grpcConfiguration: this.grpcConfig.withDeadlineMillis(clientTimeout), + maxIdleMillis: this.maxIdleMillis, + }); + } +} diff --git a/packages/core/test/unit/config/transport/transport-strategy.test.ts b/packages/client-sdk-nodejs/test/unit/config/transport/transport-strategy.test.ts similarity index 98% rename from packages/core/test/unit/config/transport/transport-strategy.test.ts rename to packages/client-sdk-nodejs/test/unit/config/transport/transport-strategy.test.ts index 55726633d..6f6f380ce 100644 --- a/packages/core/test/unit/config/transport/transport-strategy.test.ts +++ b/packages/client-sdk-nodejs/test/unit/config/transport/transport-strategy.test.ts @@ -1,7 +1,7 @@ import { StaticGrpcConfiguration, StaticTransportStrategy, -} from '../../../../src/config/transport/transport-strategy'; +} from '../../../../src'; describe('StaticGrpcConfiguration', () => { const testDeadlineMillis = 90210; diff --git a/packages/client-sdk-web/src/cache-client-props.ts b/packages/client-sdk-web/src/cache-client-props.ts new file mode 100644 index 000000000..bd5e1a907 --- /dev/null +++ b/packages/client-sdk-web/src/cache-client-props.ts @@ -0,0 +1,22 @@ +import {CredentialProvider} from '.'; +import {Configuration} from './config/configuration'; + +export interface CacheClientProps { + /** + * Configuration settings for the cache client + */ + configuration: Configuration; + /** + * controls how the client will get authentication information for connecting to the Momento service + */ + credentialProvider: CredentialProvider; + /** + * the default time to live of object inside of cache, in seconds + */ + defaultTtlSeconds: number; +} + +/** + * @deprecated use {CacheClientProps} instead + */ +export type SimpleCacheClientProps = CacheClientProps; diff --git a/packages/client-sdk-web/src/cache-client.ts b/packages/client-sdk-web/src/cache-client.ts index e9458e13f..b3c2690f1 100644 --- a/packages/client-sdk-web/src/cache-client.ts +++ b/packages/client-sdk-web/src/cache-client.ts @@ -1,10 +1,6 @@ import {ControlClient} from './internal/control-client'; import {DataClient} from './internal/data-client'; import {PingClient} from './internal/ping-client'; -import { - CredentialProvider, - NoopMomentoLoggerFactory, -} from '@gomomento/sdk-core'; import { AbstractCacheClient, IControlClient, @@ -12,10 +8,7 @@ import { IDataClient, IPingClient, } from '@gomomento/sdk-core/dist/src/internal/clients'; - -export interface CacheClientProps { - credentialProvider: CredentialProvider; -} +import {CacheClientProps} from './cache-client-props'; export class CacheClient extends AbstractCacheClient implements ICacheClient { constructor(props: CacheClientProps) { @@ -28,28 +21,14 @@ export class CacheClient extends AbstractCacheClient implements ICacheClient { function createControlClient(props: CacheClientProps): IControlClient { return new ControlClient({ - // TODO - // TODO - // TODO these shouldn't be hard-coded - // TODO - // TODO - configuration: { - getLoggerFactory: () => new NoopMomentoLoggerFactory(), - }, + configuration: props.configuration, credentialProvider: props.credentialProvider, }); } function createDataClient(props: CacheClientProps): IDataClient { return new DataClient({ - // TODO - // TODO - // TODO these shouldn't be hard-coded - // TODO - // TODO - configuration: { - getLoggerFactory: () => new NoopMomentoLoggerFactory(), - }, + configuration: props.configuration, credentialProvider: props.credentialProvider, defaultTtlSeconds: 60, }); @@ -57,14 +36,7 @@ function createDataClient(props: CacheClientProps): IDataClient { function createPingClient(props: CacheClientProps): IPingClient { return new PingClient({ - // TODO - // TODO - // TODO these shouldn't be hard-coded - // TODO - // TODO endpoint: props.credentialProvider.getCacheEndpoint(), - configuration: { - getLoggerFactory: () => new NoopMomentoLoggerFactory(), - }, + configuration: props.configuration, }); } diff --git a/packages/client-sdk-web/src/config/configuration.ts b/packages/client-sdk-web/src/config/configuration.ts index 778601524..e10c11cc3 100644 --- a/packages/client-sdk-web/src/config/configuration.ts +++ b/packages/client-sdk-web/src/config/configuration.ts @@ -1,4 +1,5 @@ import {MomentoLoggerFactory} from '@gomomento/sdk-core'; +import {TransportStrategy} from './transport'; export interface ConfigurationProps { /** @@ -6,11 +7,10 @@ export interface ConfigurationProps { */ loggerFactory: MomentoLoggerFactory; - // TODO /** * Configures low-level options for network interactions with the Momento service */ - // transportStrategy: TransportStrategy; + transportStrategy: TransportStrategy; } /** @@ -25,22 +25,55 @@ export interface Configuration { */ getLoggerFactory(): MomentoLoggerFactory; - // /** - // * @returns {TransportStrategy} the current configuration options for wire interactions with the Momento service - // */ - // getTransportStrategy(): TransportStrategy; - - // /** - // * Copy constructor for overriding TransportStrategy - // * @param {TransportStrategy} transportStrategy - // * @returns {Configuration} a new Configuration object with the specified TransportStrategy - // */ - // withTransportStrategy(transportStrategy: TransportStrategy): Configuration; - - // /** - // * Convenience copy constructor that updates the client-side timeout setting in the TransportStrategy - // * @param {number} clientTimeoutMillis - // * @returns {Configuration} a new Configuration object with its TransportStrategy updated to use the specified client timeout - // */ - // withClientTimeoutMillis(clientTimeoutMillis: number): Configuration; + /** + * @returns {TransportStrategy} the current configuration options for wire interactions with the Momento service + */ + getTransportStrategy(): TransportStrategy; + + /** + * Copy constructor for overriding TransportStrategy + * @param {TransportStrategy} transportStrategy + * @returns {Configuration} a new Configuration object with the specified TransportStrategy + */ + withTransportStrategy(transportStrategy: TransportStrategy): Configuration; + + /** + * Convenience copy constructor that updates the client-side timeout setting in the TransportStrategy + * @param {number} clientTimeoutMillis + * @returns {Configuration} a new Configuration object with its TransportStrategy updated to use the specified client timeout + */ + withClientTimeoutMillis(clientTimeoutMillis: number): Configuration; +} + +export class CacheConfiguration implements Configuration { + private readonly loggerFactory: MomentoLoggerFactory; + private readonly transportStrategy: TransportStrategy; + + constructor(props: ConfigurationProps) { + this.loggerFactory = props.loggerFactory; + this.transportStrategy = props.transportStrategy; + } + + getLoggerFactory(): MomentoLoggerFactory { + return this.loggerFactory; + } + + getTransportStrategy(): TransportStrategy { + return this.transportStrategy; + } + + withTransportStrategy(transportStrategy: TransportStrategy): Configuration { + return new CacheConfiguration({ + loggerFactory: this.loggerFactory, + transportStrategy: transportStrategy, + }); + } + + withClientTimeoutMillis(clientTimeout: number): Configuration { + return new CacheConfiguration({ + loggerFactory: this.loggerFactory, + transportStrategy: + this.transportStrategy.withClientTimeoutMillis(clientTimeout), + }); + } } diff --git a/packages/client-sdk-web/src/config/configurations.ts b/packages/client-sdk-web/src/config/configurations.ts new file mode 100644 index 000000000..09a8f76e7 --- /dev/null +++ b/packages/client-sdk-web/src/config/configurations.ts @@ -0,0 +1,152 @@ +import {CacheConfiguration} from './configuration'; +import { + DefaultMomentoLoggerFactory, + MomentoLoggerFactory, +} from '@gomomento/sdk-core'; +import { + GrpcConfiguration, + StaticGrpcConfiguration, + StaticTransportStrategy, + TransportStrategy, +} from './transport'; + +const defaultLoggerFactory: MomentoLoggerFactory = + new DefaultMomentoLoggerFactory(); + +/** + * Laptop config provides defaults suitable for a medium-to-high-latency dev environment. Permissive timeouts, retries, and + * relaxed latency and throughput targets. + * @export + * @class Laptop + */ +export class Laptop extends CacheConfiguration { + /** + * Provides the latest recommended configuration for a laptop development environment. NOTE: this configuration may + * change in future releases to take advantage of improvements we identify for default configurations. + * @param {MomentoLoggerFactory} [loggerFactory=defaultLoggerFactory] + * @returns {CacheConfiguration} + */ + static latest( + loggerFactory: MomentoLoggerFactory = defaultLoggerFactory + ): CacheConfiguration { + return Laptop.v1(loggerFactory); + } + + /** + * Provides v1 recommended configuration for a laptop development environment. This configuration is guaranteed not + * to change in future releases of the Momento node.js SDK. + * @param {MomentoLoggerFactory} [loggerFactory=defaultLoggerFactory] + * @returns {CacheConfiguration} + */ + static v1( + loggerFactory: MomentoLoggerFactory = defaultLoggerFactory + ): CacheConfiguration { + const deadlineMillis = 5000; + const grpcConfig: GrpcConfiguration = new StaticGrpcConfiguration({ + deadlineMillis: deadlineMillis, + }); + const transportStrategy: TransportStrategy = new StaticTransportStrategy({ + grpcConfiguration: grpcConfig, + }); + return new Laptop({ + loggerFactory: loggerFactory, + transportStrategy: transportStrategy, + }); + } +} + +class InRegionDefault extends CacheConfiguration { + /** + * Provides the latest recommended configuration for a typical in-region environment. NOTE: this configuration may + * change in future releases to take advantage of improvements we identify for default configurations. + * @param {MomentoLoggerFactory} [loggerFactory=defaultLoggerFactory] + * @returns {CacheConfiguration} + */ + static latest( + loggerFactory: MomentoLoggerFactory = defaultLoggerFactory + ): CacheConfiguration { + return InRegionDefault.v1(loggerFactory); + } + + /** + * Provides v1 recommended configuration for a typical in-region environment. This configuration is guaranteed not + * to change in future releases of the Momento node.js SDK. + * @param {MomentoLoggerFactory} [loggerFactory=defaultLoggerFactory] + * @returns {CacheConfiguration} + */ + static v1( + loggerFactory: MomentoLoggerFactory = defaultLoggerFactory + ): CacheConfiguration { + const deadlineMillis = 1100; + const grpcConfig: GrpcConfiguration = new StaticGrpcConfiguration({ + deadlineMillis: deadlineMillis, + }); + const transportStrategy: TransportStrategy = new StaticTransportStrategy({ + grpcConfiguration: grpcConfig, + }); + return new InRegionDefault({ + loggerFactory: loggerFactory, + transportStrategy: transportStrategy, + }); + } +} + +class InRegionLowLatency extends CacheConfiguration { + /** + * Provides the latest recommended configuration for an in-region environment with aggressive low-latency requirements. + * NOTE: this configuration may change in future releases to take advantage of improvements we identify for default + * configurations. + * @param {MomentoLoggerFactory} [loggerFactory=defaultLoggerFactory] + * @returns {CacheConfiguration} + */ + static latest( + loggerFactory: MomentoLoggerFactory = defaultLoggerFactory + ): CacheConfiguration { + return InRegionLowLatency.v1(loggerFactory); + } + + /** + * Provides v1 recommended configuration for an in-region environment with aggressive low-latency requirements. + * This configuration is guaranteed not to change in future releases of the Momento node.js SDK. + * @param {MomentoLoggerFactory} [loggerFactory=defaultLoggerFactory] + * @returns {CacheConfiguration} + */ + static v1( + loggerFactory: MomentoLoggerFactory = defaultLoggerFactory + ): CacheConfiguration { + const deadlineMillis = 500; + const grpcConfig: GrpcConfiguration = new StaticGrpcConfiguration({ + deadlineMillis: deadlineMillis, + }); + const transportStrategy: TransportStrategy = new StaticTransportStrategy({ + grpcConfiguration: grpcConfig, + }); + return new InRegionDefault({ + loggerFactory: loggerFactory, + transportStrategy: transportStrategy, + }); + } +} + +/** + * InRegion provides defaults suitable for an environment where your client is running in the same region as the Momento + * service. It has more aggressive timeouts and retry behavior than the Laptop config. + * @export + * @class InRegion + */ +export class InRegion { + /** + * This config prioritizes throughput and client resource utilization. It has a slightly relaxed client-side timeout + * setting to maximize throughput. + * @type {InRegionDefault} + */ + static Default = InRegionDefault; + /** + * This config prioritizes keeping p99.9 latencies as low as possible, potentially sacrificing + * some throughput to achieve this. It has a very aggressive client-side timeout. Use this + * configuration if the most important factor is to ensure that cache unavailability doesn't force + * unacceptably high latencies for your own application. + * @type {InRegionLowLatency} + */ + static LowLatency = InRegionLowLatency; +} diff --git a/packages/core/src/config/transport/grpc-configuration.ts b/packages/client-sdk-web/src/config/transport/grpc-configuration.ts similarity index 50% rename from packages/core/src/config/transport/grpc-configuration.ts rename to packages/client-sdk-web/src/config/transport/grpc-configuration.ts index 8abf4a68f..1ea225f6f 100644 --- a/packages/core/src/config/transport/grpc-configuration.ts +++ b/packages/client-sdk-web/src/config/transport/grpc-configuration.ts @@ -4,11 +4,6 @@ export interface GrpcConfigurationProps { * with a DeadlineExceeded error. */ deadlineMillis: number; - /** - * the maximum amount of memory, in megabytes, that a session is allowed to consume. Sessions that consume - * more than this amount will return a ResourceExhausted error. - */ - maxSessionMemoryMb: number; } /** @@ -29,17 +24,4 @@ export interface GrpcConfiguration { * @returns {GrpcConfiguration} a new GrpcConfiguration with the specified client-side deadline */ withDeadlineMillis(deadlineMillis: number): GrpcConfiguration; - - /** - * @returns {number} the maximum amount of memory, in megabytes, that a session is allowed to consume. Sessions that consume - * more than this amount will return a ResourceExhausted error. - */ - getMaxSessionMemoryMb(): number; - - /** - * Copy constructor for overriding the max session memory - * @param {number} maxSessionMemoryMb the desired maximum amount of memory, in megabytes, to allow a client session to consume - * @returns {GrpcConfiguration} a new GrpcConfiguration with the specified maximum memory - */ - withMaxSessionMemoryMb(maxSessionMemoryMb: number): GrpcConfiguration; } diff --git a/packages/core/src/config/transport/index.ts b/packages/client-sdk-web/src/config/transport/index.ts similarity index 100% rename from packages/core/src/config/transport/index.ts rename to packages/client-sdk-web/src/config/transport/index.ts diff --git a/packages/client-sdk-web/src/config/transport/transport-strategy.ts b/packages/client-sdk-web/src/config/transport/transport-strategy.ts new file mode 100644 index 000000000..5a9c497e4 --- /dev/null +++ b/packages/client-sdk-web/src/config/transport/transport-strategy.ts @@ -0,0 +1,72 @@ +import {GrpcConfiguration, GrpcConfigurationProps} from './grpc-configuration'; + +export interface TransportStrategy { + /** + * Configures the low-level gRPC settings for the Momento client's communication + * with the Momento server. + * @returns {GrpcConfiguration} + */ + getGrpcConfig(): GrpcConfiguration; + + /** + * Copy constructor for overriding the gRPC configuration + * @param {GrpcConfiguration} grpcConfig + * @returns {TransportStrategy} a new TransportStrategy with the specified gRPC config. + */ + withGrpcConfig(grpcConfig: GrpcConfiguration): TransportStrategy; + + /** + * Copy constructor to update the client-side timeout + * @param {number} clientTimeoutMillis + * @returns {TransportStrategy} a new TransportStrategy with the specified client timeout + */ + withClientTimeoutMillis(clientTimeoutMillis: number): TransportStrategy; +} + +export interface TransportStrategyProps { + /** + * low-level gRPC settings for communication with the Momento server + */ + grpcConfiguration: GrpcConfiguration; +} + +export class StaticGrpcConfiguration implements GrpcConfiguration { + private readonly deadlineMillis: number; + constructor(props: GrpcConfigurationProps) { + this.deadlineMillis = props.deadlineMillis; + } + + getDeadlineMillis(): number { + return this.deadlineMillis; + } + + withDeadlineMillis(deadlineMillis: number): StaticGrpcConfiguration { + return new StaticGrpcConfiguration({ + deadlineMillis: deadlineMillis, + }); + } +} + +export class StaticTransportStrategy implements TransportStrategy { + private readonly grpcConfig: GrpcConfiguration; + + constructor(props: TransportStrategyProps) { + this.grpcConfig = props.grpcConfiguration; + } + + getGrpcConfig(): GrpcConfiguration { + return this.grpcConfig; + } + + withGrpcConfig(grpcConfig: GrpcConfiguration): StaticTransportStrategy { + return new StaticTransportStrategy({ + grpcConfiguration: grpcConfig, + }); + } + + withClientTimeoutMillis(clientTimeout: number): StaticTransportStrategy { + return new StaticTransportStrategy({ + grpcConfiguration: this.grpcConfig.withDeadlineMillis(clientTimeout), + }); + } +} diff --git a/packages/client-sdk-web/src/index.ts b/packages/client-sdk-web/src/index.ts index dee38d525..daf12f96e 100644 --- a/packages/client-sdk-web/src/index.ts +++ b/packages/client-sdk-web/src/index.ts @@ -1,6 +1,7 @@ import {CacheClient} from './cache-client'; import {AuthClient} from './auth-client'; import {TopicClient} from './topic-client'; +import * as Configurations from './config/configurations'; // Cache Client Response Types import * as CacheGet from '@gomomento/sdk-core/dist/src/messages/responses/cache-get'; @@ -99,6 +100,7 @@ export { ItemType, SortedSetOrder, Configuration, + Configurations, CacheClient, AuthClient, CacheInfo, diff --git a/packages/client-sdk-web/src/internal/data-client.ts b/packages/client-sdk-web/src/internal/data-client.ts index a5dcabf65..c128e660f 100644 --- a/packages/client-sdk-web/src/internal/data-client.ts +++ b/packages/client-sdk-web/src/internal/data-client.ts @@ -131,6 +131,7 @@ export class DataClient< private readonly logger: MomentoLogger; private readonly authHeaders: {authorization: string}; private readonly defaultTtlSeconds: number; + private readonly deadlineMillis: number; /** * @param {DataClientProps} props @@ -147,6 +148,10 @@ export class DataClient< `Creating data client using endpoint: '${props.credentialProvider.getCacheEndpoint()}` ); + this.deadlineMillis = props.configuration + .getTransportStrategy() + .getGrpcConfig() + .getDeadlineMillis(); this.defaultTtlSeconds = props.defaultTtlSeconds; this.authHeaders = {authorization: props.credentialProvider.getAuthToken()}; this.clientWrapper = new cache.ScsClient( @@ -180,7 +185,7 @@ export class DataClient< ): Promise { const request = new _GetRequest(); request.setCacheKey(key); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.get( @@ -263,7 +268,7 @@ export class DataClient< request.setCacheKey(key); request.setCacheBody(value); request.setTtlMilliseconds(this.convertSecondsToMilliseconds(ttlSeconds)); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.set( request, @@ -324,7 +329,7 @@ export class DataClient< request.setCacheKey(key); request.setCacheBody(field); request.setTtlMilliseconds(ttlMilliseconds); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.setIfNotExists( @@ -381,7 +386,7 @@ export class DataClient< ): Promise { const request = new _DeleteRequest(); request.setCacheKey(key); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.delete( request, @@ -437,7 +442,7 @@ export class DataClient< request.setCacheKey(field); request.setAmount(amount); request.setTtlMilliseconds(ttlMilliseconds); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.increment( @@ -480,7 +485,7 @@ export class DataClient< ): Promise { const request = new _SetFetchRequest(); request.setSetName(setName); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.setFetch( request, @@ -536,7 +541,7 @@ export class DataClient< request.setElementsList(elements); request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.setUnion( request, @@ -588,7 +593,7 @@ export class DataClient< request.setSetName(setName); request.setSubtrahend(subtrahend); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.setDifference( request, @@ -662,7 +667,7 @@ export class DataClient< request.setRefreshTtl(refreshTtl); request.setTruncateFrontToSize(truncateFrontToSize || 0); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listConcatenateBack( request, @@ -736,7 +741,7 @@ export class DataClient< request.setRefreshTtl(refreshTtl); request.setTruncateBackToSize(truncateBackToSize || 0); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listConcatenateFront( request, @@ -806,7 +811,7 @@ export class DataClient< } else { request.setUnboundedEnd(new _Unbounded()); } - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listFetch( @@ -893,7 +898,7 @@ export class DataClient< } else { request.setUnboundedEnd(new _Unbounded()); } - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listRetain( @@ -938,7 +943,7 @@ export class DataClient< ): Promise { const request = new _ListLengthRequest(); request.setListName(listName); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listLength( @@ -993,7 +998,7 @@ export class DataClient< ): Promise { const request = new _ListPopBackRequest(); request.setListName(listName); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listPopBack( @@ -1046,7 +1051,7 @@ export class DataClient< ): Promise { const request = new _ListPopFrontRequest(); request.setListName(listName); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listPopFront( @@ -1121,7 +1126,7 @@ export class DataClient< request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); request.setTruncateFrontToSize(truncateFrontToSize || 0); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listPushBack( request, @@ -1188,7 +1193,7 @@ export class DataClient< request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); request.setTruncateBackToSize(truncateBackToSize || 0); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listPushFront( request, @@ -1240,7 +1245,7 @@ export class DataClient< const request = new _ListRemoveRequest(); request.setListName(listName); request.setAllElementsWithValue(value); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.listRemove( request, @@ -1309,7 +1314,7 @@ export class DataClient< request.setItemsList([item]); request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.dictionarySet( request, @@ -1379,7 +1384,7 @@ export class DataClient< request.setItemsList(elements); request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.dictionarySet( request, @@ -1436,7 +1441,7 @@ export class DataClient< const request = new _DictionaryGetRequest(); request.setDictionaryName(dictionaryName); request.setFieldsList([field]); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.dictionaryGet( @@ -1526,7 +1531,7 @@ export class DataClient< const request = new _DictionaryGetRequest(); request.setDictionaryName(dictionaryName); request.setFieldsList(this.convertArrayToB64Strings(fields)); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.dictionaryGet( @@ -1590,7 +1595,7 @@ export class DataClient< ): Promise { const request = new _DictionaryFetchRequest(); request.setDictionaryName(dictionaryName); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.dictionaryFetch( request, @@ -1672,7 +1677,7 @@ export class DataClient< request.setAmount(amount); request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.dictionaryIncrement( request, @@ -1732,7 +1737,7 @@ export class DataClient< const request = new _DictionaryDeleteRequest(); request.setDictionaryName(dictionaryName); request.setSome(new _DictionaryDeleteRequest.Some().addFields(field)); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.dictionaryDelete( request, @@ -1788,7 +1793,7 @@ export class DataClient< const request = new _DictionaryDeleteRequest(); request.setDictionaryName(dictionaryName); request.setSome(new _DictionaryDeleteRequest.Some().setFieldsList(fields)); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.dictionaryDelete( @@ -1878,7 +1883,7 @@ export class DataClient< request.setWithScores(true); request.setByIndex(by_index); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetFetch( request, @@ -2012,7 +2017,7 @@ export class DataClient< request.setWithScores(true); request.setByScore(by_score); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetFetch( request, @@ -2116,7 +2121,7 @@ export class DataClient< request.setElementsList([elem]); request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetPut( request, @@ -2185,7 +2190,7 @@ export class DataClient< request.setElementsList(elements); request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetPut( request, @@ -2269,7 +2274,7 @@ export class DataClient< const request = new _SortedSetGetScoreRequest(); request.setSetName(sortedSetName); request.setValuesList(values); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetGetScore( request, @@ -2353,7 +2358,7 @@ export class DataClient< const request = new _SortedSetGetRankRequest(); request.setSetName(sortedSetName); request.setValue(value); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetGetRank( request, @@ -2433,7 +2438,7 @@ export class DataClient< request.setAmount(amount); request.setTtlMilliseconds(ttlMilliseconds); request.setRefreshTtl(refreshTtl); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetIncrement( request, @@ -2495,7 +2500,7 @@ export class DataClient< const request = new _SortedSetRemoveRequest(); request.setSetName(sortedSetName); request.setSome(new _SortedSetRemoveRequest._Some().setValuesList([value])); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetRemove( request, @@ -2553,7 +2558,7 @@ export class DataClient< const request = new _SortedSetRemoveRequest(); request.setSetName(sortedSetName); request.setSome(new _SortedSetRemoveRequest._Some().setValuesList(values)); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.sortedSetRemove( request, @@ -2594,7 +2599,7 @@ export class DataClient< ): Promise { const request = new _ItemGetTypeRequest(); request.setCacheKey(key); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.deadlineMillis); return await new Promise(resolve => { this.clientWrapper.itemGetType( request, diff --git a/packages/client-sdk-web/src/internal/pubsub-client.ts b/packages/client-sdk-web/src/internal/pubsub-client.ts index 19af1c9d2..b3da0d13d 100644 --- a/packages/client-sdk-web/src/internal/pubsub-client.ts +++ b/packages/client-sdk-web/src/internal/pubsub-client.ts @@ -3,6 +3,7 @@ import * as cachepubsub_pb from '@gomomento/generated-types-webtext/dist/cachepu import {Configuration} from '../config/configuration'; import { CredentialProvider, + InvalidArgumentError, MomentoLogger, TopicItem, UnknownError, @@ -35,8 +36,8 @@ export class PubsubClient< private readonly client: pubsub.PubsubClient; private readonly configuration: Configuration; protected readonly credentialProvider: CredentialProvider; - // private readonly unaryRequestTimeoutMs: number; - // private static readonly DEFAULT_REQUEST_TIMEOUT_MS: number = 5 * 1000; + private readonly requestTimeoutMs: number; + private static readonly DEFAULT_REQUEST_TIMEOUT_MS: number = 5 * 1000; protected readonly logger: MomentoLogger; private readonly authHeaders: {authorization: string}; private readonly unaryInterceptors: UnaryInterceptor[]; @@ -51,16 +52,13 @@ export class PubsubClient< this.credentialProvider = props.credentialProvider; this.logger = this.configuration.getLoggerFactory().getLogger(this); - // TODO: - // TODO: uncomment after Configuration plumbing is in place . . . - // TODO - // const grpcConfig = this.configuration - // .getTransportStrategy() - // .getGrpcConfig(); - // - // this.validateRequestTimeout(grpcConfig.getDeadlineMillis()); - // this.unaryRequestTimeoutMs = - // grpcConfig.getDeadlineMillis() || PubsubClient.DEFAULT_REQUEST_TIMEOUT_MS; + const grpcConfig = this.configuration + .getTransportStrategy() + .getGrpcConfig(); + + this.validateRequestTimeout(grpcConfig.getDeadlineMillis()); + this.requestTimeoutMs = + grpcConfig.getDeadlineMillis() || PubsubClient.DEFAULT_REQUEST_TIMEOUT_MS; this.logger.debug( `Creating topic client using endpoint: '${this.credentialProvider.getCacheEndpoint()}'` ); @@ -85,17 +83,14 @@ export class PubsubClient< return endpoint; } - // TODO: - // TODO: uncomment after Configuration plumbing is in place . . . - // TODO - // private validateRequestTimeout(timeout?: number) { - // this.logger.debug(`Request timeout ms: ${String(timeout)}`); - // if (timeout !== undefined && timeout <= 0) { - // throw new InvalidArgumentError( - // 'request timeout must be greater than zero.' - // ); - // } - // } + private validateRequestTimeout(timeout?: number) { + this.logger.debug(`Request timeout ms: ${String(timeout)}`); + if (timeout !== undefined && timeout <= 0) { + throw new InvalidArgumentError( + 'request timeout must be greater than zero.' + ); + } + } protected async sendPublish( cacheName: string, @@ -113,7 +108,7 @@ export class PubsubClient< request.setCacheName(cacheName); request.setTopic(topicName); request.setValue(topicValue); - const metadata = createMetadata(cacheName); + const metadata = createMetadata(cacheName, this.requestTimeoutMs); return await new Promise(resolve => { this.client.publish( @@ -256,8 +251,6 @@ export class PubsubClient< private initializeUnaryInterceptors( headers: Header[] - // configuration: Configuration, - // requestTimeoutMs: number ): UnaryInterceptor[] { return [ new HeaderInterceptorProvider( diff --git a/packages/client-sdk-web/src/utils/web-client-utils.ts b/packages/client-sdk-web/src/utils/web-client-utils.ts index 1dc9c46c2..b31642d5f 100644 --- a/packages/client-sdk-web/src/utils/web-client-utils.ts +++ b/packages/client-sdk-web/src/utils/web-client-utils.ts @@ -7,6 +7,10 @@ export function convertToB64String(v: string | Uint8Array): string { return btoa(String.fromCharCode.apply(null, v)); } -export function createMetadata(cacheName: string): {cache: string} { - return {cache: cacheName}; +export function createMetadata( + cacheName: string, + timeoutMillis: number +): {cache: string; deadline: string} { + const deadline = Date.now() + timeoutMillis; + return {cache: cacheName, deadline: deadline.toString()}; } diff --git a/packages/client-sdk-web/test/integration/integration-setup.ts b/packages/client-sdk-web/test/integration/integration-setup.ts index 285b51b02..8710294b4 100644 --- a/packages/client-sdk-web/test/integration/integration-setup.ts +++ b/packages/client-sdk-web/test/integration/integration-setup.ts @@ -1,31 +1,36 @@ -import {AuthClient, CacheClient, TopicClient} from '../../src'; import { deleteCacheIfExists, testCacheName, } from '@gomomento/common-integration-tests'; import { + AuthClient, CreateCache, - CredentialProvider, + Configurations, DeleteCache, - NoopMomentoLoggerFactory, -} from '@gomomento/sdk-core'; + CacheClient, + CredentialProvider, + TopicClient, +} from '../../src'; import {ITopicClient} from '@gomomento/sdk-core/dist/src/internal/clients'; +import {CacheClientProps} from '../../src/cache-client-props'; const credsProvider = CredentialProvider.fromEnvironmentVariable({ environmentVariableName: 'TEST_AUTH_TOKEN', }); -function momentoClientForTesting() { - return new CacheClient({ - credentialProvider: credsProvider, - }); +export const IntegrationTestCacheClientProps: CacheClientProps = { + configuration: Configurations.Laptop.latest(), + credentialProvider: credsProvider, + defaultTtlSeconds: 1111, +}; + +function momentoClientForTesting(): CacheClient { + return new CacheClient(IntegrationTestCacheClientProps); } -function momentoTopicClientForTesting(): ITopicClient { +function momentoTopicClientForTesting(): TopicClient { return new TopicClient({ - configuration: { - getLoggerFactory: () => new NoopMomentoLoggerFactory(), - }, + configuration: Configurations.Laptop.latest(), credentialProvider: credsProvider, }); } diff --git a/packages/client-sdk-web/test/integration/ping.test.ts b/packages/client-sdk-web/test/integration/ping.test.ts index c5e68e050..e0e669fa4 100644 --- a/packages/client-sdk-web/test/integration/ping.test.ts +++ b/packages/client-sdk-web/test/integration/ping.test.ts @@ -1,29 +1,25 @@ -import { - CredentialProvider, - MomentoLoggerFactory, - NoopMomentoLoggerFactory, -} from '@gomomento/sdk-core'; -import {CacheClient} from '../../src'; +import {CredentialProvider} from '@gomomento/sdk-core'; +import {CacheClient, Configurations} from '../../src'; import {PingClient} from '../../src/internal/ping-client'; import {expectWithMessage} from '@gomomento/common-integration-tests'; +import {CacheClientProps} from '../../src/cache-client-props'; describe('ping service', () => { it('ping should work', async () => { - const cacheClient = new CacheClient({ + const cacheClientProps: CacheClientProps = { + configuration: Configurations.Laptop.latest(), credentialProvider: CredentialProvider.fromEnvironmentVariable({ environmentVariableName: 'TEST_AUTH_TOKEN', }), - }); + defaultTtlSeconds: 1111, + }; + const cacheClient = new CacheClient(cacheClientProps); await cacheClient.ping(); }); it('should fail on bad URL', async () => { const pingClient = new PingClient({ endpoint: 'bad.url', - configuration: { - getLoggerFactory(): MomentoLoggerFactory { - return new NoopMomentoLoggerFactory(); - }, - }, + configuration: Configurations.Laptop.latest(), }); try { await pingClient.ping(); diff --git a/packages/client-sdk-web/test/unit/config/transport/transport-strategy.test.ts b/packages/client-sdk-web/test/unit/config/transport/transport-strategy.test.ts new file mode 100644 index 000000000..2c5296def --- /dev/null +++ b/packages/client-sdk-web/test/unit/config/transport/transport-strategy.test.ts @@ -0,0 +1,53 @@ +import { + StaticGrpcConfiguration, + StaticTransportStrategy, +} from '../../../../src/config/transport'; + +describe('StaticGrpcConfiguration', () => { + const testDeadlineMillis = 90210; + const testGrpcConfiguration = new StaticGrpcConfiguration({ + deadlineMillis: testDeadlineMillis, + }); + + it('should support overriding deadline millis', () => { + const newDeadlineMillis = 42; + const configWithNewDeadline = + testGrpcConfiguration.withDeadlineMillis(newDeadlineMillis); + expect(configWithNewDeadline.getDeadlineMillis()).toEqual( + newDeadlineMillis + ); + }); +}); + +describe('StaticTransportStrategy', () => { + const testDeadlineMillis = 90210; + const testGrpcConfiguration = new StaticGrpcConfiguration({ + deadlineMillis: testDeadlineMillis, + }); + + const testTransportStrategy = new StaticTransportStrategy({ + grpcConfiguration: testGrpcConfiguration, + }); + + it('should support overriding grpc config', () => { + const newDeadlineMillis = 42; + const newGrpcConfig = new StaticGrpcConfiguration({ + deadlineMillis: newDeadlineMillis, + }); + const strategyWithNewGrpcConfig = + testTransportStrategy.withGrpcConfig(newGrpcConfig); + expect(strategyWithNewGrpcConfig.getGrpcConfig()).toEqual(newGrpcConfig); + }); + + it('should support overriding client timeout', () => { + const newClientTimeout = 42; + const expectedGrpcConfig = new StaticGrpcConfiguration({ + deadlineMillis: newClientTimeout, + }); + const strategyWithNewClientTimeout = + testTransportStrategy.withClientTimeoutMillis(newClientTimeout); + expect(strategyWithNewClientTimeout.getGrpcConfig()).toEqual( + expectedGrpcConfig + ); + }); +}); diff --git a/packages/core/src/config/transport/transport-strategy.ts b/packages/core/src/config/transport/transport-strategy.ts deleted file mode 100644 index 5c4d8167f..000000000 --- a/packages/core/src/config/transport/transport-strategy.ts +++ /dev/null @@ -1,134 +0,0 @@ -import {GrpcConfiguration, GrpcConfigurationProps} from './grpc-configuration'; - -export interface TransportStrategyProps { - /** - * low-level gRPC settings for communication with the Momento server - */ - grpcConfiguration: GrpcConfiguration; - /** - * The maximum duration for which a connection may remain idle before being replaced. This - * setting can be used to force re-connection of a client if it has been idle for too long. - * In environments such as AWS lambda, if the lambda is suspended for too long the connection - * may be closed by the load balancer, resulting in an error on the subsequent request. If - * this setting is set to a duration less than the load balancer timeout, we can ensure that - * the connection will be refreshed to avoid errors. - * @returns {number} - */ - maxIdleMillis: number; -} - -/** - * Configures the network options for communicating with the Momento service. - * @export - * @interface TransportStrategy - */ -export interface TransportStrategy { - /** - * Configures the low-level gRPC settings for the Momento client's communication - * with the Momento server. - * @returns {GrpcConfiguration} - */ - getGrpcConfig(): GrpcConfiguration; - - /** - * Copy constructor for overriding the gRPC configuration - * @param {GrpcConfiguration} grpcConfig - * @returns {TransportStrategy} a new TransportStrategy with the specified gRPC config. - */ - withGrpcConfig(grpcConfig: GrpcConfiguration): TransportStrategy; - - /** - * Copy constructor to update the client-side timeout - * @param {number} clientTimeoutMillis - * @returns {TransportStrategy} a new TransportStrategy with the specified client timeout - */ - withClientTimeoutMillis(clientTimeoutMillis: number): TransportStrategy; - - /** - * The maximum duration for which a connection may remain idle before being replaced. This - * setting can be used to force re-connection of a client if it has been idle for too long. - * In environments such as AWS lambda, if the lambda is suspended for too long the connection - * may be closed by the load balancer, resulting in an error on the subsequent request. If - * this setting is set to a duration less than the load balancer timeout, we can ensure that - * the connection will be refreshed to avoid errors. - * @returns {number} - */ - getMaxIdleMillis(): number; - - /** - * Copy constructor to update the max idle connection timeout. (See {getMaxIdleMillis}.) - * @param {number} maxIdleMillis - * @returns {TransportStrategy} a new TransportStrategy with the specified max idle connection timeout. - */ - withMaxIdleMillis(maxIdleMillis: number): TransportStrategy; -} - -export class StaticGrpcConfiguration implements GrpcConfiguration { - private readonly deadlineMillis: number; - private readonly maxSessionMemoryMb: number; - constructor(props: GrpcConfigurationProps) { - this.deadlineMillis = props.deadlineMillis; - this.maxSessionMemoryMb = props.maxSessionMemoryMb; - } - - getDeadlineMillis(): number { - return this.deadlineMillis; - } - - getMaxSessionMemoryMb(): number { - return this.maxSessionMemoryMb; - } - - withDeadlineMillis(deadlineMillis: number): StaticGrpcConfiguration { - return new StaticGrpcConfiguration({ - deadlineMillis: deadlineMillis, - maxSessionMemoryMb: this.maxSessionMemoryMb, - }); - } - - withMaxSessionMemoryMb(maxSessionMemoryMb: number): StaticGrpcConfiguration { - return new StaticGrpcConfiguration({ - deadlineMillis: this.deadlineMillis, - maxSessionMemoryMb: maxSessionMemoryMb, - }); - } -} - -export class StaticTransportStrategy implements TransportStrategy { - private readonly grpcConfig: GrpcConfiguration; - private readonly maxIdleMillis: number; - - constructor(props: TransportStrategyProps) { - this.grpcConfig = props.grpcConfiguration; - this.maxIdleMillis = props.maxIdleMillis; - } - - getGrpcConfig(): GrpcConfiguration { - return this.grpcConfig; - } - - withGrpcConfig(grpcConfig: GrpcConfiguration): StaticTransportStrategy { - return new StaticTransportStrategy({ - grpcConfiguration: grpcConfig, - maxIdleMillis: this.maxIdleMillis, - }); - } - - getMaxIdleMillis(): number { - return this.maxIdleMillis; - } - - withMaxIdleMillis(maxIdleMillis: number): TransportStrategy { - return new StaticTransportStrategy({ - grpcConfiguration: this.grpcConfig, - maxIdleMillis: maxIdleMillis, - }); - } - - withClientTimeoutMillis(clientTimeout: number): StaticTransportStrategy { - return new StaticTransportStrategy({ - grpcConfiguration: this.grpcConfig.withDeadlineMillis(clientTimeout), - maxIdleMillis: this.maxIdleMillis, - }); - } -}