15 个不稳定版本 (7 个破坏性版本)
0.8.0 | 2024 年 1 月 24 日 |
---|---|
0.7.1 | 2023 年 8 月 28 日 |
0.6.1 | 2023 年 4 月 13 日 |
0.5.4 | 2022 年 4 月 5 日 |
0.1.0 | 2021 年 2 月 2 日 |
#25 in 缓存
每月 111 次下载
88KB
1K SLoC
bkt
bkt
(发音为 "bucket")是一个用 Rust 编写的子进程缓存实用工具,受 bash-cache 的启发。使用 bkt
包装昂贵的进程调用允许调用者重用最近的调用,而不会复杂化其应用程序逻辑。这在 shell 提示、交互式应用程序(如 fzf
)以及轮询其他进程的长运行程序中很有用。
bkt
作为独立二进制文件以及 Rust 库 提供。有关库文档,请参阅 https://docs.rs/bkt/。本 README 涵盖了 bkt
二进制文件。
安装
运行 cargo install bkt
编译和安装 bkt
。如果您系统上尚未安装 cargo
,则需要 安装 cargo
。
常见平台的预编译二进制文件附在每个 版本(从 0.5 开始)。如果您希望发布包括更多平台二进制文件,请提出问题或发送 PR。
正在跟踪包管理器支持 此处;欢迎志愿者。
用法
bkt [--ttl=DURATION] [--stale=DURATION] [--cwd] [--env=ENV ...] [--modtime=FILE ...] [--scope=SCOPE] [--discard-failures] [--warm|--force] -- <command>...
使用 bkt
最简单的方法是在您打算缓存的命令前加上 bkt --
前缀,例如
# Execute and cache an invocation of 'date +%s.%N'
$ bkt -- date +%s.%N
1631992417.080884000
# A subsequent invocation reuses the same cached output
$ bkt -- date +%s.%N
1631992417.080884000
当 bkt
接收到它之前(或最近)未看到的命令时,它将同步执行该命令,并缓存其 stdout、stderr 和退出代码。再次使用相同命令调用 bkt
将从缓存中读取数据,并输出仿佛该命令再次运行一样。
缓存有效期
有两个标志 --ttl
和 --stale
,用于配置缓存数据的保留时间。默认情况下,bkt
使用 60 秒的 TTL(存活时间),这意味着超过六十秒的缓存数据将被丢弃,并重新执行后台命令。通过传递不同的值,例如 --ttl=1d
,将改变缓存数据被视为有效的时间。默认的 TTL 可以通过定义一个 BKT_TTL
环境变量来覆盖。
当数据过期时,bkt
必须同步重新执行命令,这可能会引入意外的延迟。为了避免这种情况,传递 --stale
与 TTL 的时间长度更短。当缓存数据超过过期阈值时,这将导致 bkt
在后台刷新缓存,同时仍然及时返回缓存的数据。
这两个标志(以及 BKT_TTL
)接受持续时间字符串,如 10s
或 1hour 30min
。确切的语法由 humantime 库定义。
执行环境
某些命令的行为不仅取决于命令行参数。可以调整 bkt
缓存这些命令的方式,以便无关的调用被分别缓存。
工作目录
例如,默认情况下尝试缓存 pwd
不会按预期工作
$ $ bkt -- pwd
/tmp/foo
$ cd ../bar
# Cached output for 'pwd' is reused even though the directory has changed
$ bkt -- pwd
/tmp/foo
要使 bkt
不仅要根据命令行参数,还要根据当前工作目录进行缓存,请传递 --cwd
$ bkt --cwd -- pwd
/tmp/foo
$ cd ../bar
$ bkt --cwd -- pwd
/tmp/bar
环境变量
同样,要指定一个或多个环境变量作为缓存的命令的相关变量,请使用 --env
,例如 --env=LANG
。此标志可以多次提供,以根据其他变量进行缓存。具有给定变量不同值的调用将被分别缓存。
文件修改
还可以让 bkt
检查一个或多个文件的最后修改时间,并使用 --modtime
将其包含在缓存键中。例如,传递 --modtime=/etc/passwd
将导致在 /etc/passwd
修改时重新执行后台命令。
手动刷新
还可以使用 --force
或 --warm
触发刷新。前者的行为与缓存数据未找到时完全相同,执行进程并缓存结果。这在你知道缓存数据不再是最新的情况下很有用,例如,因为外部更改了某些东西。
或者,可以使用 --warm
提供的异步刷新缓存。这将在后台触发刷新,但立即结束当前进程而不输出。这在你预期不久将会有额外的调用并希望确保它们获得缓存命中时很有用。请注意,直到预热过程完成,并发调用仍然可能看到缓存未命中并触发它们自己的调用。
设置缓存范围
缓存数据将持久化到磁盘(但请参阅以下 内容),并且对调用 bkt
的任何进程都可用。通常这是所希望的,但某些用法可能希望将它们的调用与其他可能的并发调用隔离。
为此,请使用足够独特的参数传递 --scope=...
,例如调用程序的固定标签、当前进程 ID 或时间戳。
$ bkt -- date +%s.%N
1631992417.080884000
# Changing the scope causes the command to be cached separately
$ bkt --scope=foo -- date +%s.%N
1631992418.010562000
或者,定义一个 BKT_SCOPE
环境变量来配置调用之间的统一范围。这在脚本中很有用,可以确保所有命令共享一个范围。
#!/bin/bash
# Set a unique scope for this script invocation using the PID and current time
export BKT_SCOPE="my_script_$$_$(date -Ins)"
丢弃失败的调用
默认情况下,所有调用都会被缓存,无论它们的输出或退出代码如何。在应该不缓存失败的情况下,通过传递--discard-failures
来仅保留成功的调用(返回0
退出代码的调用)。
警告:传递此标志可能会导致支持命令的调用频率高于--ttl
所建议的,这反过来又可能产生意外的负载。如果支持命令由于中断或错误(如过载的网站)而失败,触发额外的调用可能会加剧问题,实际上会导致DDoS攻击受影响的系统。通常,不设置此标志,而是使客户端能够应对偶尔的失败,会更安全。
更改缓存目录
默认情况下,缓存数据存储在/tmp
或类似的临时目录下;可以通过--cache-dir
标志或通过定义BKT_CACHE_DIR
环境变量来自定义。
如果定义了BKT_TMPDIR
环境变量,则将使用它而不是系统的临时目录。尽管BKT_TMPDIR
和BKT_CACHE_DIR
具有类似的效果,但BKT_TMPDIR
旨在用于配置全局缓存位置(例如,通过在您的.bashrc
或类似的文件中声明),而--cache-dir
/BKT_CACHE_DIR
应用于自定义特定调用集的缓存位置,这些调用集不应使用默认缓存目录。
请注意,目录的选择可能会影响bkt
的性能:如果缓存存储在tmpfs
或固态分区下,它将比缓存到机械硬盘快得多。
安全和隐私
默认缓存目录可能是世界可读的。在Unix上,缓存目录以700
权限创建,这意味着只有当前用户可以访问它,但这并非万无一失。
您可以将缓存目录自定义(见上面)到一个您信任的位置,例如~/.bkt
,但请注意,您的家目录可能比默认选择的临时目录慢。
一般来说,如果您不是系统上的唯一用户,最好将您的TMPDIR
配置为只有您可以访问的位置。如果不可能,请使用BKT_TMPDIR
配置一个专门为bkt
配置的自定义临时目录。
模式和技巧
请在讨论板上分享您如何使用bkt
!
加快fzf
和其他预览工具的速度
bkt
与执行其他命令的交互式工具(如fzf
)配合良好。由于fzf
在每次选择元素时都会执行--preview
命令,因此当命令执行时间较长时,浏览可能会变得缓慢且繁琐。使用bkt
允许为每个选择缓存预览。比较
$ printf '%s\n' 1 0.2 3 0.1 5 | \
fzf --preview="bash -c 'sleep {}; echo {}'"
$ printf '%s\n' 1 0.2 3 0.1 5 | \
fzf --preview="bkt --ttl=10m --stale=10s -- bash -c 'sleep {}; echo {}'"
通常情况下,您希望使用较长的TTL和较短的过期时间,这样即使您让 fzf
运行一段时间,缓存也能保持活跃并在后台刷新。如果您希望在下一次调用时使缓存失效,也可以设置一个 --scope
。
请参阅 这个讨论,以获取更完整的使用 bkt
和 fzf
的示例,包括在用户开始导航选择器之前预热命令。
仅在安装 bkt
时使用
您可能想要分发使用 bkt
的shell脚本,而无需每个用户都安装 bkt
。通过将 bkt
包装在shell函数中,您的脚本可以在 bkt
可用的情况下干净地调用它,而不会复杂化用户的流程。当然,如果他们选择安装 bkt
,他们将以更快的脚本作为结果!
# Cache commands using bkt if installed
if command -v bkt >&/dev/null; then
bkt() { command bkt "$@"; }
else
# If bkt isn't installed skip its arguments and just execute directly.
# Optionally write a msg to stderr suggesting users install bkt.
bkt() {
while [[ "$1" == --* ]]; do shift; done
"$@"
}
fi
# Now you can call bkt (the function) just like you'd call bkt (the binary):
bkt -- expensive_cmd ...
在shell脚本中使用 bkt
装饰命令
有时在shell脚本或您的shell环境中缓存一个命令的所有调用是有帮助的。您可以使用类似于 bash-cache 的装饰函数模式来透明地启用缓存,如下所示
# This is Bash syntax, but other shells support similar syntax
expensive_cmd() {
bkt [bkt args ...] -- expensive_cmd "$@"
}
现在,对shell中的 expensive_cmd
的调用将通过 bkt
在幕后进行。这可以用于简洁和一致性,但显然改变这种行为是双刃剑,所以请谨慎使用。如果您需要绕过单个调用的缓存,Bash 提供了 command
内置命令,因此 command expensive_cmd ...
将直接调用 expensive_cmd
。其他shell也提供了类似的功能。
依赖关系
~4–13MB
~166K SLoC