Skip to content

Commit 2d3ef31

Browse files
committed
Idempotent stuff
1 parent 323c476 commit 2d3ef31

File tree

1 file changed

+66
-4
lines changed

1 file changed

+66
-4
lines changed

book.org

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@
223223
foo "${a[@]}"
224224
#+end_src
225225

226-
227226
** Read lines from file
228227
The =read= command we used just above is part of the usual idiom to
229228
read a file line by line.
@@ -1353,9 +1352,6 @@
13531352
With this, you can find out how many matches happened in that
13541353
line. The example above filters lines which have 2 words from the
13551354
'foo|bar|baz' regex.
1356-
1357-
1358-
13591355
*** Set operations
13601356
There are lots of other "set level" operations you can perform on
13611357
files/streams using basic unix tools.
@@ -1966,7 +1962,15 @@ coprocs would mess up your inline functions.
19661962
and if the user forgets any, the shell will barf.
19671963

19681964
** Idempotent functions
1965+
Being able to call the same function multiple times even if you just
1966+
called it, without having to account for "oh, did this already happen
1967+
or not?" but instead have a mental model of "I need this to have
1968+
happened after this function call", and consider it done, is very
1969+
liberating from the code perspective.
19691970

1971+
Also, there are subgoals, like caching slow functions, downloads, etc.
1972+
1973+
*** nop subsequent calls
19701974
"My favourite shell scripting function definition technique:
19711975
idempotent functions by redefining the function as a noop inside
19721976
its body:
@@ -1980,6 +1984,64 @@ coprocs would mess up your inline functions.
19801984
echo "This bit will only be executed on the first foo call"
19811985
}
19821986
#+end_src
1987+
*** Download once
1988+
A function might be sideffecty, as in "download files". These sort of
1989+
cases, you want to download the file only if you haven't downloaded it
1990+
yet.
1991+
1992+
=cache= here gets a cache "id" where it'll store the results of =http=
1993+
and next time, when called with the same param, it will reuse the saved version.
1994+
1995+
This pattern applies to many kinds of functions, so with slight
1996+
modifications you can adapt it.
1997+
1998+
#+begin_src bash
1999+
cache() {
2000+
local path=$CACHE_DIR/$1
2001+
[[ -f $path ]] && cat $path && return 0
2002+
2003+
shift
2004+
$@ | tee $path
2005+
2006+
return 1
2007+
}
2008+
2009+
get_repos() {
2010+
local url="https://api.github.com/search/repositories?q=user:$USER&access_token=$GITHUB_TOKEN&per_page=100&page=$1"
2011+
cache $USER-repos-$1 http $url
2012+
}
2013+
#+end_src
2014+
2015+
*** memoize with ttl, with ttl
2016+
What if you want to cache for some time?
2017+
2018+
The tricks here:
2019+
2020+
- Use a file as a sentinel for the cache.
2021+
- Create a file, set it's modification date to now()+12hours
2022+
- check with `-nt` (newer than) and a temporary file (to have a
2023+
=now()= value in "file" format).
2024+
2025+
#+begin_src bash
2026+
hmacache="/tmp/.hmacache"
2027+
is_recent_cache() {
2028+
[ "$hmacache" -nt <(echo 1) ]
2029+
}
2030+
update_cache() {
2031+
touch -m -t "$(date -v+12H +"%Y%m%d%H%M.%S")" "$hmacache"
2032+
}
2033+
2034+
main() {
2035+
#...
2036+
if ! is_recent_cache ; then
2037+
if ! curl -s https://hello.ts.net > /dev/null; then
2038+
die "Tailscale must be connected to start Harbormaster"
2039+
fi
2040+
# other slow checks
2041+
update_cache
2042+
fi
2043+
}
2044+
#+end_src
19832045

19842046
* Debugging
19852047
** adding =bash= to a script to debug

0 commit comments

Comments
 (0)