diff options
| -rwxr-xr-x | server.py | 8 | ||||
| -rw-r--r-- | src/config.toml | 18 | ||||
| -rw-r--r-- | src/content/_index.md | 17 | ||||
| -rw-r--r-- | src/content/blog/_index.md | 1 | ||||
| -rw-r--r-- | src/content/blog/distributed-hooks.md | 131 | ||||
| -rw-r--r-- | src/content/contact/_index.md | 3 | ||||
| -rw-r--r-- | src/static/hl-dark.css | 113 | ||||
| -rw-r--r-- | src/static/hl-light.css | 99 |
8 files changed, 249 insertions, 141 deletions
@@ -6,9 +6,11 @@ import os class NoCacheHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): def end_headers(self): - self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate') # HTTP 1.1 - self.send_header('Pragma', 'no-cache') # HTTP 1.0 - self.send_header('Expires', '0') # Proxies + self.send_header( + "Cache-Control", "no-cache, no-store, must-revalidate" + ) # HTTP 1.1 + self.send_header("Pragma", "no-cache") # HTTP 1.0 + self.send_header("Expires", "0") # Proxies super().end_headers() diff --git a/src/config.toml b/src/config.toml index 3e400aa..8205d22 100644 --- a/src/config.toml +++ b/src/config.toml @@ -15,12 +15,14 @@ compile_sass = true minify_html = false # Keep this false, as it may cause issues with some styles build_search_index = false # Keep this false, search is temporarily unsupported generate_feeds = false # Whether to generate a feed file in root, read docs for more info about rss feed -feed_filenames = ["feed.xml"] # "feed.xml" | "atom.xml" | "rss.xml", read docs for more info +feed_filenames = [ + "feed.xml", +] # "feed.xml" | "atom.xml" | "rss.xml", read docs for more info taxonomies = [ - { name = "science", feed = true}, - { name = "tags" }, - { name = "categories" } + { name = "science", feed = true }, + { name = "tags" }, + { name = "categories" }, ] [markdown] @@ -55,14 +57,14 @@ sections = [ blog_section_path = "/blog" back_link_text = "Back" # Text of the back button -force_theme = false # false | "light" | "dark" +force_theme = false # false | "light" | "dark" footer_copyright = "© 2025 Benedikt Peetz" -footer_credits = true # Whether to show "Built with zola and serene" in footer +footer_credits = true # Whether to show "Built with zola and serene" in footer not_found_error_text = "404 Not Found" not_found_recover_text = "« back to home »" -reaction = false # Whether to enable anonymous emoji reactions (Note: You need to set up a working api endpoint to enable this feature) -reaction_align = "right" # "left" | "center" | "right" +reaction = false # Whether to enable anonymous emoji reactions (Note: You need to set up a working api endpoint to enable this feature) +reaction_align = "right" # "left" | "center" | "right" reaction_endpoint = "https://example.com/api/reaction" diff --git a/src/content/_index.md b/src/content/_index.md index 653077d..c20314f 100644 --- a/src/content/_index.md +++ b/src/content/_index.md @@ -5,21 +5,26 @@ template = 'home.html' lang = 'en' # Show footer in home page + footer = true # If you don't want to display id/bio/avatar, simply comment out that line + name = "Benedikt Peetz" id = "bpeetz" bio = "he/him" + # avatar = "img/avatar.webp" -links = [ - { name = "Git", icon = "git", url = "https://git.foss-syndicate.org/bpeetz" }, - { name = "Email", icon = "email", url = "mailto:benedikt.peetz@b-peetz.de" }, - { name = "Matrix", icon = "matrix", url = "https://matrix.to/#/@soispha:matrix.vhack.eu" }, - { name = "Signal", icon = "signal", url = "https://signal.me/#eu/r03RJhrEynGMYVMhhpGuirRRMJYm_Yjgys3gfQPayVlQmb0Bv25Pt4_HT9QYpa7w" }, -] + +links = \[ +{ name = "Git", icon = "git", url = "https://git.foss-syndicate.org/bpeetz" }, +{ name = "Email", icon = "email", url = "mailto:benedikt.peetz@b-peetz.de" }, +{ name = "Matrix", icon = "matrix", url = "https://matrix.to/#/@soispha:matrix.vhack.eu" }, +{ name = "Signal", icon = "signal", url = "https://signal.me/#eu/r03RJhrEynGMYVMhhpGuirRRMJYm_Yjgys3gfQPayVlQmb0Bv25Pt4_HT9QYpa7w" }, +\] # Show a few recent posts in home page + recent = true recent_max = 15 recent_more_text = "more »" diff --git a/src/content/blog/_index.md b/src/content/blog/_index.md index 838b240..43cf722 100644 --- a/src/content/blog/_index.md +++ b/src/content/blog/_index.md @@ -11,6 +11,7 @@ generate_feeds = true lang = "en" title = "Blog" + # subtitle = "I write about ...." date_format = "%b %-d, %Y" diff --git a/src/content/blog/distributed-hooks.md b/src/content/blog/distributed-hooks.md index b32c743..211ea25 100644 --- a/src/content/blog/distributed-hooks.md +++ b/src/content/blog/distributed-hooks.md @@ -2,33 +2,33 @@ title = "An collection of my toughs regarding hooks in a fully distributed system" date = 2025-04-25 +++ + <!-- LTeX: language=en-GB --> ## Hooks in a distributed system -We assume that our distributed system (system for short), contains in -total one task set. This task set is synced via multiple replicas and, -most importantly, not one replica owns it. As such a replica needs to -synchronize with every other replica to be able to claim, that they own -the full task set. +We assume that our distributed system (system for short), contains in total one +task set. This task set is synced via multiple replicas and, most importantly, +not one replica owns it. As such a replica needs to synchronize with every other +replica to be able to claim, that they own the full task set. -We just assume, that each of the replicas can perfectly synchronize -itself. +We just assume, that each of the replicas can perfectly synchronize itself. -What if a user wanted to run a hook on ever new input to this task set -(i.e., on every new task)? +What if a user wanted to run a hook on ever new input to this task set (i.e., on +every new task)? Where would the hook execution happen? - ### 1. The naive way (e.g. Taskwarrior or git) -You could simply run the hook in the client that adds/modifies the task to the task set. -At first, this approach might look very promising: -It is easy, gives the user direct feedback about the hook return status (and thus allows to use the hook as a filter) and most importantly it is completely transparent for the user. +You could simply run the hook in the client that adds/modifies the task to the +task set. At first, this approach might look very promising: It is easy, gives +the user direct feedback about the hook return status (and thus allows to use +the hook as a filter) and most importantly it is completely transparent for the +user. -The problem with this approach is unfortunately not fixable. -Take for example following setup: +The problem with this approach is unfortunately not fixable. Take for example +following setup: ``` | Desktop |---------------------------- | Smartphone | @@ -36,70 +36,97 @@ Take for example following setup: +--------------| Laptop |-----------------+ ``` -And assume, that all of them have access to a client, that can add task to the task set. -Now assume, that I have a hook that connects to a server and starts a time there. +And assume, that all of them have access to a client, that can add task to the +task set. Now assume, that I have a hook that connects to a server and starts a +time there. -If I were to start a task on my desktop, the hook would fire and tell the server to start time tracking. -If I later stop the task on my laptop, the hook would fire again and tell the server to stop tracking time. -This works flawlessly, as the server was already tracking time and as such can stop doing so. +If I were to start a task on my desktop, the hook would fire and tell the server +to start time tracking. If I later stop the task on my laptop, the hook would +fire again and tell the server to stop tracking time. This works flawlessly, as +the server was already tracking time and as such can stop doing so. -Let's imagine a different approach: -I start the task on my smartphone, which has a client that is not able to run hooks directly, as my smartphone lacks a full Linux system. -Now, trying to stop the task on my laptop, raises an error with the server, as the task was never started. +Let's imagine a different approach: I start the task on my smartphone, which has +a client that is not able to run hooks directly, as my smartphone lacks a full +Linux system. Now, trying to stop the task on my laptop, raises an error with +the server, as the task was never started. -In this case, we would need a way to track that the smartphone has not yet started the time on the server. -And that this should happen once the replica on the laptop got a hold of the task (i.e., it synchronized itself with the replica on the smartphone). +In this case, we would need a way to track that the smartphone has not yet +started the time on the server. And that this should happen once the replica on +the laptop got a hold of the task (i.e., it synchronized itself with the replica +on the smartphone). ### 2. Centralized approach (e.g. Git on servers) -The “easy” way out is simply promoting on of the replicas to be our point of centralization. -This replica could then run the hook for every new input it receives via synchronization. +The “easy” way out is simply promoting on of the replicas to be our point of +centralization. This replica could then run the hook for every new input it +receives via synchronization. -After a full synchronization with every other replica out there, we know that the hook was run exactly once for each task. +After a full synchronization with every other replica out there, we know that +the hook was run exactly once for each task. -The problem with this approach is quite apparent: -We need to promote one of the replicas. -This means that the hook can only be run, _after_ this central replica synchronized itself. -As such, filter hooks, that prevent certain tasks to be inserted into the whole task set are only run after the fact. -This also makes it necessary that the other replicas wait for this central replica to advance before they advance themselves. +The problem with this approach is quite apparent: We need to promote one of the +replicas. This means that the hook can only be run, _after_ this central replica +synchronized itself. As such, filter hooks, that prevent certain tasks to be +inserted into the whole task set are only run after the fact. This also makes it +necessary that the other replicas wait for this central replica to advance +before they advance themselves. -This approach is quite similar to git's branches. -Our central replica would be the main branch, and all the other replicas would than rebase themselves regularly on the main branch. +This approach is quite similar to git's branches. Our central replica would be +the main branch, and all the other replicas would than rebase themselves +regularly on the main branch. ### 3. Distributed Tracking -Having now explained why both running the task directly on the client, and running it in a centralized replica has downsides, I would like to point out my third idea. +Having now explained why both running the task directly on the client, and +running it in a centralized replica has downsides, I would like to point out my +third idea. What if we combine these approaches? -A client marks a task at replica addition time, with the hooks that it has already executed (in our example above the server timer start/stop hook). -If a replica synchronizes itself and receives a task, which has not yet recorded hook execution, it will execute them instead of the original client. +A client marks a task at replica addition time, with the hooks that it has +already executed (in our example above the server timer start/stop hook). If a +replica synchronizes itself and receives a task, which has not yet recorded hook +execution, it will execute them instead of the original client. Have you noticed the problem in this approach? -Exactly! Hooks now need to be idempotent and can possibly be executed at an arbitrary time _after_ the original task was added: +Exactly! Hooks now need to be idempotent and can possibly be executed at an +arbitrary time _after_ the original task was added: -My smartphone client, marks the new task as having not run any hooks, as such _both_ my desktop and my laptop will run the server time tracking hook. -This will than fail on the later run, as the server cannot start time tracking for an already started task. -Additionally, the second hook run could also happen _after_ the task was already stopped (marking it started again)! +My smartphone client, marks the new task as having not run any hooks, as such +_both_ my desktop and my laptop will run the server time tracking hook. This +will than fail on the later run, as the server cannot start time tracking for an +already started task. Additionally, the second hook run could also happen +_after_ the task was already stopped (marking it started again)! As such we exchanged having no hook execution, for one prone to race conditions. - ### 4. Hook execution on every client -Having seen, that working around client hook execution does not really work (cf. approach 2 or 3), we could also go the other way and give all clients the possibility to execute hooks. +Having seen, that working around client hook execution does not really work (cf. +approach 2 or 3), we could also go the other way and give all clients the +possibility to execute hooks. This would require two things: -1. Hooks need to be somehow synchronized between clients (you cannot expect someone, to manually sync a hook script with a mobile client) -2. Hooks can no longer be undefined executable blobs. They need to be constricted, to a subset of executables (e.g., to Lua/python/web assembly). - -With these two requirements in place, a client could ship a Lua/python/web assembly runtime and thus guarantee that it can execute all possible hooks. -There is a big problem with this approach. -It breaks probably most of the current hooks, because they are either written in a not-included language like POSIX shell (which cannot be included, because it probably hard-depends on binary dependencies (GNU `coreutils` as the most prevalent) which cannot be introspected from the outside) or are written in one of the included languages, but depend on external dependencies (many python hooks, for example, try to execute `task` to perform further task operations). +1. Hooks need to be somehow synchronized between clients (you cannot expect + someone, to manually sync a hook script with a mobile client) +1. Hooks can no longer be undefined executable blobs. They need to be + constricted, to a subset of executables (e.g., to Lua/python/web assembly). -In general, this approach would probably require a sandbox of some sort for hooks, so that hook authors know that their hook will also work on other platforms. -If we limit hooks to a subset of possible options, we should also enforce it on the platforms with more possibilities, so that hook authors can be confident that their hook actually works everywhere. +With these two requirements in place, a client could ship a Lua/python/web +assembly runtime and thus guarantee that it can execute all possible hooks. +There is a big problem with this approach. It breaks probably most of the +current hooks, because they are either written in a not-included language like +POSIX shell (which cannot be included, because it probably hard-depends on +binary dependencies (GNU `coreutils` as the most prevalent) which cannot be +introspected from the outside) or are written in one of the included languages, +but depend on external dependencies (many python hooks, for example, try to +execute `task` to perform further task operations). +In general, this approach would probably require a sandbox of some sort for +hooks, so that hook authors know that their hook will also work on other +platforms. If we limit hooks to a subset of possible options, we should also +enforce it on the platforms with more possibilities, so that hook authors can be +confident that their hook actually works everywhere. diff --git a/src/content/contact/_index.md b/src/content/contact/_index.md index a8a4284..fcc5cc3 100644 --- a/src/content/contact/_index.md +++ b/src/content/contact/_index.md @@ -10,7 +10,6 @@ lang = 'en' title = "Contact" subtitle = "How to contact me" - math = false mermaid = false copy = false @@ -19,11 +18,13 @@ reaction = false +++ Currently, you can reach me via the following methods: + - [Email – benedikt.peetz@b-peetz.de](mailto:benedikt.peetz@b-peetz.de) - [Matrix – @soispha:vhack.eu](https://matrix.to/#/@soispha:matrix.vhack.eu) - [Signal – benedikt.32](https://signal.me/#/eu/r03RJhrEynGMYVMhhpGuirRRMJYm_Yjgys3gfQPayVlQmb0Bv25Pt4_HT9QYpa7w) You can find my published PGP key via the web key directory: + ``` sq network wkd search benedikt.peetz@b-peetz.de --output - ``` diff --git a/src/static/hl-dark.css b/src/static/hl-dark.css index da26983..abfd5c1 100644 --- a/src/static/hl-dark.css +++ b/src/static/hl-dark.css @@ -3,70 +3,107 @@ */ .z-code { - color: #c5c8c6; + color: #c5c8c6; } -.z-comment, .z-string.z-quoted.z-double.z-block.z-python { - color: #999999; +.z-comment, +.z-string.z-quoted.z-double.z-block.z-python { + color: #999999; } -.z-keyword.z-operator.z-class, .z-constant.z-other, .z-source.z-php.z-embedded.z-line { - color: #ced1cf; +.z-keyword.z-operator.z-class, +.z-constant.z-other, +.z-source.z-php.z-embedded.z-line { + color: #ced1cf; } -.z-variable, .z-support.z-other.z-variable, .z-string.z-other.z-link, .z-string.z-regexp, .z-entity.z-name.z-tag, .z-entity.z-other.z-attribute-name, .z-meta.z-tag, .z-declaration.z-tag { - color: #a67878; +.z-variable, +.z-support.z-other.z-variable, +.z-string.z-other.z-link, +.z-string.z-regexp, +.z-entity.z-name.z-tag, +.z-entity.z-other.z-attribute-name, +.z-meta.z-tag, +.z-declaration.z-tag { + color: #a67878; } -.z-constant.z-numeric, .z-constant.z-language, .z-support.z-constant, .z-constant.z-character, .z-variable.z-parameter, .z-punctuation.z-section.z-embedded, .z-keyword.z-other.z-unit { - color: #e08355; +.z-constant.z-numeric, +.z-constant.z-language, +.z-support.z-constant, +.z-constant.z-character, +.z-variable.z-parameter, +.z-punctuation.z-section.z-embedded, +.z-keyword.z-other.z-unit { + color: #e08355; } -.z-type, .z-entity.z-name.z-class, .z-entity.z-name.z-type.z-class, .z-support.z-type, .z-support.z-class { - color: #83aaa5; +.z-type, +.z-entity.z-name.z-class, +.z-entity.z-name.z-type.z-class, +.z-support.z-type, +.z-support.z-class { + color: #83aaa5; } -.z-string, .z-constant.z-other.z-symbol, .z-entity.z-other.z-inherited-class, .z-markup.z-heading { - color: #85ad74; +.z-string, +.z-constant.z-other.z-symbol, +.z-entity.z-other.z-inherited-class, +.z-markup.z-heading { + color: #85ad74; } -.z-keyword.z-operator, .z-constant.z-other.z-color { - color: #83aaa5; +.z-keyword.z-operator, +.z-constant.z-other.z-color { + color: #83aaa5; } -.z-entity.z-name.z-function, .z-meta.z-function-call, .z-support.z-function, .z-keyword.z-other.z-special-method, .z-meta.z-block-level { - color: #81a2be; +.z-entity.z-name.z-function, +.z-meta.z-function-call, +.z-support.z-function, +.z-keyword.z-other.z-special-method, +.z-meta.z-block-level { + color: #81a2be; } -.z-keyword, .z-storage, .z-storage.z-type, .z-entity.z-name.z-tag.z-css { - color: #b294bb; +.z-keyword, +.z-storage, +.z-storage.z-type, +.z-entity.z-name.z-tag.z-css { + color: #b294bb; } .z-invalid { - color: #ced2cf; - background-color: #df5f5f; + color: #ced2cf; + background-color: #df5f5f; } .z-meta.z-separator { - color: #ced2cf; - background-color: #82a3bf; + color: #ced2cf; + background-color: #82a3bf; } .z-invalid.z-deprecated { - color: #ced2cf; - background-color: #b798bf; + color: #ced2cf; + background-color: #b798bf; } -.z-markup.z-inserted.z-diff, .z-markup.z-deleted.z-diff, .z-meta.z-diff.z-header.z-to-file, .z-meta.z-diff.z-header.z-from-file { - color: #ffffff; +.z-markup.z-inserted.z-diff, +.z-markup.z-deleted.z-diff, +.z-meta.z-diff.z-header.z-to-file, +.z-meta.z-diff.z-header.z-from-file { + color: #ffffff; } -.z-markup.z-inserted.z-diff, .z-meta.z-diff.z-header.z-to-file { - color: #4baf5c; +.z-markup.z-inserted.z-diff, +.z-meta.z-diff.z-header.z-to-file { + color: #4baf5c; } -.z-markup.z-deleted.z-diff, .z-meta.z-diff.z-header.z-from-file { - color: #d46565; +.z-markup.z-deleted.z-diff, +.z-meta.z-diff.z-header.z-from-file { + color: #d46565; } -.z-meta.z-diff.z-header.z-from-file, .z-meta.z-diff.z-header.z-to-file { - color: #4271ae; +.z-meta.z-diff.z-header.z-from-file, +.z-meta.z-diff.z-header.z-to-file { + color: #4271ae; } .z-meta.z-diff.z-range { - color: #3e999f; -font-style: italic; + color: #3e999f; + font-style: italic; } .z-markup.z-deleted { - color: #f92672; + color: #f92672; } .z-markup.z-inserted { - color: #a6e22e; + color: #a6e22e; } .z-markup.z-changed { - color: #967efb; + color: #967efb; } diff --git a/src/static/hl-light.css b/src/static/hl-light.css index acb83c5..d983d43 100644 --- a/src/static/hl-light.css +++ b/src/static/hl-light.css @@ -3,58 +3,91 @@ */ .z-code { - color: #4d4d4c; + color: #4d4d4c; } -.z-comment, .z-string.z-quoted.z-double.z-block.z-python { - color: #999999; +.z-comment, +.z-string.z-quoted.z-double.z-block.z-python { + color: #999999; } -.z-keyword.z-operator.z-class, .z-constant.z-other, .z-source.z-php.z-embedded.z-line { - color: #666969; +.z-keyword.z-operator.z-class, +.z-constant.z-other, +.z-source.z-php.z-embedded.z-line { + color: #666969; } -.z-variable, .z-support.z-other.z-variable, .z-string.z-other.z-link, .z-string.z-regexp, .z-entity.z-name.z-tag, .z-entity.z-other.z-attribute-name, .z-meta.z-tag, .z-declaration.z-tag { - color: #a67878; +.z-variable, +.z-support.z-other.z-variable, +.z-string.z-other.z-link, +.z-string.z-regexp, +.z-entity.z-name.z-tag, +.z-entity.z-other.z-attribute-name, +.z-meta.z-tag, +.z-declaration.z-tag { + color: #a67878; } -.z-constant.z-numeric, .z-constant.z-language, .z-support.z-constant, .z-constant.z-character, .z-variable.z-parameter, .z-punctuation.z-section.z-embedded, .z-keyword.z-other.z-unit { - color: #e08355; +.z-constant.z-numeric, +.z-constant.z-language, +.z-support.z-constant, +.z-constant.z-character, +.z-variable.z-parameter, +.z-punctuation.z-section.z-embedded, +.z-keyword.z-other.z-unit { + color: #e08355; } -.z-type, .z-entity.z-name.z-class, .z-entity.z-name.z-type.z-class, .z-support.z-type, .z-support.z-class { - color: #568a8f; +.z-type, +.z-entity.z-name.z-class, +.z-entity.z-name.z-type.z-class, +.z-support.z-type, +.z-support.z-class { + color: #568a8f; } -.z-string, .z-constant.z-other.z-symbol, .z-entity.z-other.z-inherited-class, .z-markup.z-heading { - color: #85ad74; +.z-string, +.z-constant.z-other.z-symbol, +.z-entity.z-other.z-inherited-class, +.z-markup.z-heading { + color: #85ad74; } -.z-keyword.z-operator, .z-constant.z-other.z-color { - color: #568a8f; +.z-keyword.z-operator, +.z-constant.z-other.z-color { + color: #568a8f; } -.z-entity.z-name.z-function, .z-meta.z-function-call, .z-support.z-function, .z-keyword.z-other.z-special-method, .z-meta.z-block-level { - color: #4271ae; +.z-entity.z-name.z-function, +.z-meta.z-function-call, +.z-support.z-function, +.z-keyword.z-other.z-special-method, +.z-meta.z-block-level { + color: #4271ae; } -.z-keyword, .z-storage, .z-storage.z-type { - color: #8959a8; +.z-keyword, +.z-storage, +.z-storage.z-type { + color: #8959a8; } .z-invalid { - color: #ffffff; - background-color: #df5f5f; + color: #ffffff; + background-color: #df5f5f; } .z-meta.z-separator { - color: #ffffff; - background-color: #4271ae; + color: #ffffff; + background-color: #4271ae; } .z-invalid.z-deprecated { - color: #ffffff; - background-color: #8959a8; + color: #ffffff; + background-color: #8959a8; } -.z-markup.z-inserted.z-diff, .z-meta.z-diff.z-header.z-to-file { - color: #229545; +.z-markup.z-inserted.z-diff, +.z-meta.z-diff.z-header.z-to-file { + color: #229545; } -.z-markup.z-deleted.z-diff, .z-meta.z-diff.z-header.z-from-file { - color: #c82829; +.z-markup.z-deleted.z-diff, +.z-meta.z-diff.z-header.z-from-file { + color: #c82829; } -.z-meta.z-diff.z-header.z-from-file, .z-meta.z-diff.z-header.z-to-file { - color: #4271ae; +.z-meta.z-diff.z-header.z-from-file, +.z-meta.z-diff.z-header.z-to-file { + color: #4271ae; } .z-meta.z-diff.z-range { - color: #3e999f; -font-style: italic; + color: #3e999f; + font-style: italic; } |
