Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force https on request passed by engine #579

Merged
merged 41 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d331cc4
Force https on request passed by engine
mcandeia Feb 22, 2024
b5d4127
Skipping non-semver version on update task
mcandeia Feb 22, 2024
66c1f56
Set text to yellow
mcandeia Feb 22, 2024
858753c
Using AWS S3 bucket for caching.
ItamarRocha Feb 9, 2024
4e98e00
Update variable names
ItamarRocha Feb 9, 2024
e9c61e8
Add some logging for debugging
ItamarRocha Feb 14, 2024
de211f8
add timing for s3 get
ItamarRocha Feb 15, 2024
d3015aa
Update strin
ItamarRocha Feb 15, 2024
f1ac904
Add zstd compression for large files
ItamarRocha Feb 19, 2024
bf403b5
use accelerate endpoint should be faster
ItamarRocha Feb 20, 2024
7b999ca
Using express storage - aws
ItamarRocha Feb 20, 2024
bfc51ba
Remove console log messages
ItamarRocha Feb 23, 2024
90b7c9f
Back to default sao paulo bucket
ItamarRocha Feb 23, 2024
ed1b550
Sao paulo default bucket with accelaration endpoint
ItamarRocha Feb 23, 2024
033ac80
Undo loader alterations for PR
ItamarRocha Feb 26, 2024
586505a
Fix format
ItamarRocha Feb 26, 2024
d67a674
Remove unneeded logs and fix format
ItamarRocha Feb 26, 2024
359e540
Remove expiration from code, since it has to be configured on Bucket
ItamarRocha Feb 26, 2024
8796616
Add compressed flag to metric
ItamarRocha Feb 26, 2024
285e1e6
Add deno env configurable endpoint
ItamarRocha Feb 26, 2024
1c54392
Add s3 cache to loader
ItamarRocha Feb 26, 2024
efcafb5
Change default back to 5
ItamarRocha Feb 26, 2024
08bddf6
Add KV as fallback to S3
ItamarRocha Feb 26, 2024
40621f5
Add MAX_UNCOMPRESSED_SIZE to env var and refactor code
ItamarRocha Feb 26, 2024
748a331
Refactor conditions and fix format
ItamarRocha Feb 26, 2024
00840dc
Fix MAX_UNCOMPRESSED_SIZE
ItamarRocha Feb 27, 2024
9384978
Add File System as caching option
ItamarRocha Feb 28, 2024
33c1e4e
Rename caches
ItamarRocha Feb 28, 2024
fae4fba
Change default file system env var values
ItamarRocha Feb 28, 2024
bb9d704
Remove compression
ItamarRocha Feb 28, 2024
1fc732b
Create the cache directory, if it doesn't exists
ItamarRocha Feb 28, 2024
3dcbb80
Adding logging for debugging
ItamarRocha Feb 28, 2024
d0a66dd
Adding logging for debugging
ItamarRocha Feb 28, 2024
be9501b
change path
ItamarRocha Feb 28, 2024
7bdb164
Change path
ItamarRocha Feb 28, 2024
f92dd08
Add compression with env var
ItamarRocha Feb 28, 2024
1288f95
change writeTextFile to writeFile
ItamarRocha Feb 28, 2024
506e3fb
Clean file for PR
ItamarRocha Feb 28, 2024
4a1b50b
Rebase with main
mcandeia Mar 4, 2024
c9454df
Use std import
mcandeia Mar 4, 2024
5046f12
Lazy check + Write permission check
ItamarRocha Mar 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion blocks/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { Block, BlockModule, InstanceOf } from "../engine/block.ts";
import { singleFlight } from "../engine/core/utils.ts";
import { ResolverMiddlewareContext } from "../engine/middleware.ts";
import { meter } from "../observability/otel/metrics.ts";
import { caches } from "../runtime/caches/denoKV.ts";
import { caches as cachesKV } from "../runtime/caches/denoKV.ts";
import { caches as cachesFileSystem } from "../runtime/caches/fileSystem.ts";
import { HttpContext } from "./handler.ts";
import {
applyProps,
Expand Down Expand Up @@ -100,6 +101,8 @@ const stats = {

let maybeCache: Cache | undefined;

// Fallback to DenoKV if cachesFileSystem not available.
const caches = cachesFileSystem ?? cachesKV;
caches.open("loader")
.then((c) => maybeCache = c)
.catch(() => maybeCache = undefined);
Expand Down
216 changes: 216 additions & 0 deletions runtime/caches/fileSystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { logger, tracer } from "../../observability/otel/config.ts";
import { meter } from "../../observability/otel/metrics.ts";
import { ValueType } from "../../deps.ts";
import {
assertCanBeCached,
assertNoOptions,
withCacheNamespace,
} from "./common.ts";
import { existsSync } from "std/fs/mod.ts";

const FILE_SYSTEM_CACHE_DIRECTORY =
Deno.env.get("FILE_SYSTEM_CACHE_DIRECTORY") ?? undefined;

const downloadDuration = meter.createHistogram(
"file_system_cache_download_duration",
{
description: "file system cache download duration",
unit: "ms",
valueType: ValueType.DOUBLE,
},
);

const bufferSizeSumObserver = meter.createUpDownCounter("buffer_size_sum", {
description: "Sum of buffer sizes",
unit: "1",
valueType: ValueType.INT,
});

function createFileSystemCache(): CacheStorage {
async function putFile(
key: string,
responseArray: Uint8Array,
) {
const filePath = `${FILE_SYSTEM_CACHE_DIRECTORY}/${key}`;
await Deno.writeFile(filePath, responseArray);
return;
}

async function getFile(key: string) {
try {
const filePath = `${FILE_SYSTEM_CACHE_DIRECTORY}/${key}`;
const fileContent = await Deno.readFile(filePath);
return fileContent;
} catch (err) {
logger.error(`error when reading from file system, ${err}`);
return null;
}
}

async function deleteFile(key: string) {
try {
const filePath = `${FILE_SYSTEM_CACHE_DIRECTORY}/${key}`;
await Deno.remove(filePath);
return true;
} catch (err) {
logger.error(`error when deleting from file system, ${err}`);
return false;
}
}

const caches: CacheStorage = {
delete: (_cacheName: string): Promise<boolean> => {
throw new Error("Not Implemented");
},
has: (_cacheName: string): Promise<boolean> => {
throw new Error("Not Implemented");
},
keys: (): Promise<string[]> => {
throw new Error("Not Implemented");
},
match: (
_request: URL | RequestInfo,
_options?: MultiCacheQueryOptions | undefined,
): Promise<Response | undefined> => {
throw new Error("Not Implemented");
},
open: (cacheName: string): Promise<Cache> => {
const requestURLSHA1 = withCacheNamespace(cacheName);

return Promise.resolve({
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Cache/add) */
add: (_request: RequestInfo | URL): Promise<void> => {
throw new Error("Not Implemented");
},
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Cache/addAll) */
addAll: (_requests: RequestInfo[]): Promise<void> => {
throw new Error("Not Implemented");
},
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Cache/delete) */
delete: async (
request: RequestInfo | URL,
options?: CacheQueryOptions,
): Promise<boolean> => {
assertNoOptions(options);

const deleteResponse = await deleteFile(
await requestURLSHA1(request),
);
return deleteResponse;
},
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Cache/keys) */
keys: (
_request?: RequestInfo | URL,
_options?: CacheQueryOptions,
): Promise<ReadonlyArray<Request>> => {
throw new Error("Not Implemented");
},
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Cache/match) */
match: async (
request: RequestInfo | URL,
options?: CacheQueryOptions,
): Promise<Response | undefined> => {
assertNoOptions(options);
const cacheKey = await requestURLSHA1(request);
const span = tracer.startSpan("file-system-get", {
attributes: {
cacheKey,
},
});
try {
const startTime = performance.now();
const data = await getFile(cacheKey);
const downloadDurationTime = performance.now() - startTime;

span.addEvent("file-system-get-data");

if (data === null) {
span.addEvent("cache-miss");
return undefined;
}
span.addEvent("cache-hit");

downloadDuration.record(downloadDurationTime, {
bufferSize: data.length,
});

return new Response(
data,
);
} catch (err) {
span.recordException(err);
throw err;
} finally {
span.end();
}
},
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Cache/matchAll) */
matchAll: (
_request?: RequestInfo | URL,
_options?: CacheQueryOptions,
): Promise<ReadonlyArray<Response>> => {
throw new Error("Not Implemented");
},
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Cache/put) */
put: async (
request: RequestInfo | URL,
response: Response,
): Promise<void> => {
const req = new Request(request);
assertCanBeCached(req, response);

if (!response.body) {
return;
}

const cacheKey = await requestURLSHA1(request);
const buffer = await response.arrayBuffer()
.then((buffer) => new Uint8Array(buffer))
.then((buffer) => {
bufferSizeSumObserver.add(buffer.length);
return buffer;
});

const span = tracer.startSpan("file-system-put", {
attributes: {
cacheKey,
},
});

try {
try {
const setSpan = tracer.startSpan("file-system-set", {
attributes: { cacheKey },
});
putFile(cacheKey, buffer).catch(
(err) => {
console.error("file system error", err);
setSpan.recordException(err);
},
).finally(() => {
setSpan.end();
}); // do not await for setting cache
} catch (error) {
logger.error(`error saving to file system ${error?.message}`);
}
} catch (err) {
span.recordException(err);
throw err;
} finally {
span.end();
}
},
});
},
};

// Check if the cache directory exists, if not, create it
if (FILE_SYSTEM_CACHE_DIRECTORY && !existsSync(FILE_SYSTEM_CACHE_DIRECTORY)) {
Deno.mkdirSync(FILE_SYSTEM_CACHE_DIRECTORY, { recursive: true });
}
return caches;
ItamarRocha marked this conversation as resolved.
Show resolved Hide resolved
}

export const caches = FILE_SYSTEM_CACHE_DIRECTORY
? createFileSystemCache()
: undefined;
Loading
Loading