Skip to content

Commit f0d1f54

Browse files
committed
refactor: make cache generic
1 parent 543f278 commit f0d1f54

File tree

3 files changed

+23
-9
lines changed

3 files changed

+23
-9
lines changed

packages/actor-memory-expression/src/memory_calculator.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ import {
2020

2121
import { ACTOR_LIMITS } from '@apify/consts';
2222

23-
import type { LruCache } from '../../datastructures/src/lru_cache';
24-
import type { ActorRunOptions, MemoryEvaluationContext } from './types.js';
23+
import type { ActorRunOptions, CompilationCache, MemoryEvaluationContext } from './types.js';
2524

2625
// In theory, users could create expressions longer than 1000 characters,
2726
// but in practice, it's unlikely anyone would need that much complexity.
@@ -110,7 +109,7 @@ const customGetFunc = (obj: any, path: string, defaultVal?: number) => {
110109
* @param num The number to round.
111110
* @returns The closest power of 2 within min/max range.
112111
*/
113-
const roundToClosestPowerOf2 = (num: number): number | undefined => {
112+
const roundToClosestPowerOf2 = (num: number): number => {
114113
if (typeof num !== 'number' || Number.isNaN(num)) {
115114
throw new Error(`Calculated memory value is not a valid number: ${num}.`);
116115
}
@@ -190,7 +189,7 @@ const processTemplateVariables = (defaultMemoryMbytes: string): string => {
190189
* @param cache An optional cache to store/retrieve compiled expressions.
191190
* @returns The compiled EvalFunction.
192191
*/
193-
const getCompiledExpression = (expression: string, cache: LruCache<EvalFunction> | undefined): EvalFunction => {
192+
const getCompiledExpression = (expression: string, cache: CompilationCache | undefined): EvalFunction => {
194193
if (!cache) {
195194
return compile(expression);
196195
}
@@ -199,7 +198,7 @@ const getCompiledExpression = (expression: string, cache: LruCache<EvalFunction>
199198

200199
if (!compiledExpression) {
201200
compiledExpression = compile(expression);
202-
cache.add(expression, compiledExpression!);
201+
cache.set(expression, compiledExpression!);
203202
}
204203

205204
return compiledExpression;
@@ -211,12 +210,13 @@ const getCompiledExpression = (expression: string, cache: LruCache<EvalFunction>
211210
*
212211
* @param defaultMemoryMbytes The string expression to evaluate (e.g., `get(input, 'urls.length', 10) * 1024` for `input = { urls: ['url1', 'url2'] }`).
213212
* @param context The `MemoryEvaluationContext` (containing `input` and `runOptions`) available to the expression.
214-
* @returns The calculated memory value rounded to the closest power of 2 clamped within allowed limits.
213+
* @param options.cache Optional synchronous cache. Since compiled functions cannot be saved to a database/Redis, they are kept in local memory.
214+
* @returns The calculated memory value rounded to the closest power of 2 and clamped within allowed limits.
215215
*/
216216
export const calculateRunDynamicMemory = (
217217
defaultMemoryMbytes: string,
218218
context: MemoryEvaluationContext,
219-
options: { cache: LruCache<EvalFunction> } | undefined = undefined,
219+
options: { cache: CompilationCache } | undefined = undefined,
220220
) => {
221221
if (defaultMemoryMbytes.length > DEFAULT_MEMORY_MBYTES_EXPRESSION_MAX_LENGTH) {
222222
throw new Error(`The defaultMemoryMbytes expression is too long. Max length is ${DEFAULT_MEMORY_MBYTES_EXPRESSION_MAX_LENGTH} characters.`);

packages/actor-memory-expression/src/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { EvalFunction } from 'mathjs';
2+
13
export type ActorRunOptions = {
24
build?: string;
35
timeoutSecs?: number;
@@ -12,3 +14,9 @@ export type MemoryEvaluationContext = {
1214
runOptions: ActorRunOptions;
1315
input: Record<string, unknown>;
1416
}
17+
18+
export type CompilationCache = {
19+
get: (expression: string) => EvalFunction | null;
20+
set: (expression: string, compilationResult: EvalFunction) => void;
21+
length: () => number;
22+
}

test/memory_calculator.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { EvalFunction } from 'mathjs';
2+
import type { CompilationCache } from 'packages/actor-memory-expression/src/types';
23

34
import { calculateRunDynamicMemory, DEFAULT_MEMORY_MBYTES_EXPRESSION_MAX_LENGTH } from '@apify/actor-memory-expression';
45
import { LruCache } from '@apify/datastructures';
@@ -175,12 +176,17 @@ describe('calculateDefaultMemoryFromExpression', () => {
175176
});
176177

177178
describe('Caching', () => {
178-
let cache: LruCache<EvalFunction>;
179+
let cache: CompilationCache;
179180
const context = { input: { size: 10 }, runOptions: {} };
180181
const expr = 'input.size * 1024';
181182

182183
beforeEach(() => {
183-
cache = new LruCache<EvalFunction>({ maxLength: 10 });
184+
const lruCache = new LruCache<EvalFunction>({ maxLength: 10 });
185+
cache = {
186+
get: (expression: string) => lruCache.get(expression),
187+
set: (expression: string, compilationResult: EvalFunction) => lruCache.add(expression, compilationResult),
188+
length: () => lruCache.length(),
189+
};
184190
});
185191

186192
it('correctly works with cache passed in options', () => {

0 commit comments

Comments
 (0)