[{"content":"","date":"6 August 2026","externalUrl":null,"permalink":"/series/neovim/","section":"Series","summary":"","title":"Neovim","type":"series"},{"content":"","date":"6 August 2026","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"As a long-time Neovim user, I\u0026rsquo;ve always been looking for the most convenient way to review code in Neovim. After all, a Neovim setup you configured yourself is just too comfortable to leave. This post shares how I do it today, and hopefully gets more people to join the Neovim side!\nMy current setup:\nWezterm with tmux Neovim (review with the codecompanion plugin) worktrunk: worktree CLI How I got here # My current workflow is inspired by orca, an ADE (Agent Development Environment). There are a few features I really like:\nOpen multiple worktrees quickly The most useful thing in orca for me is how fast you can open and manage multiple worktrees: paste a PR link and it creates a git worktree and opens it as its own workspace. A workspace is a lot like a terminal session: you can open terminal tabs / claude tabs, and split windows. This is a big help for maintainers who review many PRs, since you can have several open at the same time, running in parallel, and switch between them freely.\nPaste a PR link and orca creates a worktree and opens it as its own workspace View the PR diff This is just the diff between the current branch and main / master. With it you don\u0026rsquo;t need to bounce back and forth to GitHub to read the diff, you can do it all in one window.\nOrca\u0026rsquo;s PR diff page: diff on the left, changed files on the right Leave comments for AI on the diff page You can open the diff page and leave comments with questions for the AI, then send them one at a time to the current AI chat / a new chat, or send all comments at once.\nLeave comments directly on the diff, then send them to the AI one by one or all at once Of course orca still has some gaps: there seems to be no editor support yet, so no go to definition (I saw issues on GitHub asking for vscode support and so on). Right now I open a terminal tab with nvim and review alongside with diffview, then jump to the matching orca diff when I need to ask the AI (a bit annoying).\nMy current setup # Here\u0026rsquo;s how my setup gets the three orca features above:\n1. Open Multiple Worktrees Quickly # This is done with worktrunk. Usage is very simple. Say I want to switch to the branch of PR 1234 to review it:\nwt switch pr:1234 It pulls the PR, creates a worktree, and switches to it. When the review is done, wt remove in the same folder removes the worktree. wt list shows all current worktrees:\nwt list shows all current worktrees Worktrunk only solves switching worktrees quickly. So how do you open several worktrees at the same time? That\u0026rsquo;s where tmux sessions come in. I won\u0026rsquo;t go into tmux sessions in detail; think of them as multiple terminal workspaces, each with its own tabs. For me, reviewing several PRs while also writing code, this is extremely useful.\nIn tmux I have a shortcut \u0026lt;leader\u0026gt; + N to quickly create a new session:\nbind-key N command-prompt -p \u0026#34;new session:\u0026#34; \u0026#34;new-session -s \u0026#39;%%\u0026#39;\u0026#34; And \u0026lt;leader\u0026gt; + s opens the sessions list:\nbind-key s choose-tree -Zs -O name 2. View the PR diff in Nvim # I think this is a really practical feature for reviewers: quickly read the diff and jump to files. In nvim I use Diffview.nvim, which can:\nShow the diff of local changes Show the diff between two commits Handle merge conflicts (it has a JetBrains-style three-way view, which I think is great) Show the commit history and diff of a single file To view a PR diff we use point 2 above, but copying the current commit and pasting it into the command every time takes too long, so I added a keymap \u0026lt;leader\u0026gt; + gd (config) to open the PR diff quickly.\nYour browser cannot play this video. Download video.\nViewing a PR diff with Diffview.nvim Note: the color theme that fits this plugin best is tokyonight. See this discussion for how to set it up (issue comment), or take a look at my config.\n3. Using AI in Nvim # This part isn\u0026rsquo;t limited to \u0026ldquo;leave comments for AI on the diff page\u0026rdquo; above. It\u0026rsquo;s about how I use AI in nvim in general (leaving comments is covered too 😄).\nThe tool I use is codecompanion.nvim. It toggles a vertical split window in nvim as the place to talk to the AI. That window is actually just a markdown file, so you can use vim motions in it. To make it easy to select a region and ask the AI about it, I added a \u0026lt;leader\u0026gt; + cs keymap in my config. It sends the selected lines to the code companion chat as @filename:line_number, which makes the whole flow much smoother.\nYour browser cannot play this video. Download video.\nBasic code companion usage On top of that, code companion recently added a code review feature, which works really well together with Diffview.nvim. Diffview already takes two windows side by side, so opening another AI chat window gets crowded. Instead, we can use the code review feature to leave comments, then send them all at once to ask the AI or have it make the changes.\nYour browser cannot play this video. Download video.\nUsing code review comments in diff view If the side window feels too small, you can move it to a new tab with nvim\u0026rsquo;s built-in Ctrl-w + T. It\u0026rsquo;s still the same buffer, so the content stays in sync.\nYour browser cannot play this video. Download video.\nOpening the AI chat in a new tab I have a few more code companion settings, like listing all comments in the quickfix list. See my config for more settings.\nWrapping up # That\u0026rsquo;s a quick tour. Feel free to check out my nvim and tmux configs.\nbtw, the latest code companion release adds herdr support. Maybe I\u0026rsquo;ll switch over and give it a try 😄\n","date":"6 August 2026","externalUrl":null,"permalink":"/posts/nvim/review-code-with-nvim/","section":"Posts","summary":"My Neovim code review setup: worktrunk, tmux sessions, Diffview.nvim and codecompanion.nvim","title":"Review code with Neovim","type":"posts"},{"content":"","date":"6 August 2026","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","date":"6 August 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"6 August 2026","externalUrl":null,"permalink":"/tags/tools/","section":"Tags","summary":"","title":"Tools","type":"tags"},{"content":" Issue link: https://github.com/ray-project/ray/issues/58213 My PR: https://github.com/ray-project/ray/pull/58914 Issue Description # Originally, cancelling threaded actor task is not supported. This issue is requesting adding the support for cancel threaded actor with an is_canceled flag to detect the cancellation.\nWe are expecting the usage like so:\n@ray.remote class SyncActor: def __init__(self): self.is_canceled = False def long_running_method(self): \u0026#34;\u0026#34;\u0026#34;A sync actor method that checks for cancellation periodically.\u0026#34;\u0026#34;\u0026#34; for i in range(100): # For sync actor tasks, is_canceled() can be checked in the task body if ray.get_runtime_context().is_canceled(): self.is_canceled = True print(\u0026#34;Actor task canceled, cleaning up...\u0026#34;) return \u0026#34;canceled\u0026#34; time.sleep(0.1) return \u0026#34;completed\u0026#34; How to cancel actor # Actor is a stateful worker that keeps the state. When calling actor method, it can access and mutate the worker\u0026rsquo;s state. While it\u0026rsquo;s stateful, it\u0026rsquo;s not safe for us to directly interrupt it like what we did for normal task, as we will lose the current state. The better way is to enable the graceful termination option so that we can clean up before termination, like what we have for async actor.\nFor async actor, it\u0026rsquo;s running in the asyncio.Task, where asyncio is the standard Python library (link). When canceling the async actor, Ray will cancel the asyncio.Task, which will raise an asyncio.CancelledError. The official document recommends us to use try/finally block to do the clean up even if we cancel the task (link)\nHere’s the example of how to start and cancel an actor. We use async actor as example here:\nimport ray import asyncio import time @ray.remote class Actor: async def f(self): try: await asyncio.sleep(5) except asyncio.CancelledError: print(\u0026#34;Actor task canceled.\u0026#34;) actor = Actor.remote() ref = actor.f.remote() # Wait until task is scheduled. time.sleep(1) # Cancel the actor with ray.cancel ray.cancel(ref) # When doing ray.get on the canceled object, the TaskCancelledError will be raised try: ray.get(ref) except ray.exceptions.TaskCancelledError: print(\u0026#34;Object reference was cancelled.\u0026#34;) Below is the brief code path on calling the ray.cancel(). Note that the place we call ray.cancel() is in the “Submitter” node, and this will be send to the “Executor” node through RPC.\nSubmitter side ray.cancel(ref) → worker.core_worker.cancel_task() (python/ray/_private/worker.py) → CCoreWorkerProcess.GetCoreWorker().CancelTask (python/ray/_raylet.pyx) → CoreWorker::CancelTask (src/ray/core_worker/core_worker.cc) → ActorTaskSubmitter::CancelTask(task_spec, recursive) If the task is in the actor’s submitter queue, can be canceled directly; otherwise send RPC: client-\u0026gt;CancelTask Threaded actor task - Executor side CoreWorker::HandleCancelTask() → CancelActorTaskOnExecutor() → TaskReceiver::CancelQueuedActorTask() → If queued, remove from queue → If running, cannot cancel (return success to avoid retry) Async actor task - Executor side CoreWorker::HandleCancelTask() → CancelActorTaskOnExecutor() → task_execution_service_.post() (into the actor event loop) If running: cancel_async_actor_task() → fut.cancel() → Python async task receives asyncio.CancelledError If queued: TaskReceiver::CancelQueuedActorTask() Originally, when the threaded actor is running, Ray will ignore the cancel signal and keep running the actor. This is what we want to solve in this issue. My solution is described in the next section.\nMy Solution # To tackle this, we need following components:\nPython API ray.get_runtime_context().is_canceled() to show that the actor is canceled\nRecord the cancellation state\nRaise TaskCanceled error when ray.get() on the cancelled task\nPython API # I started from the Python API to know where the cancellation state will be read from. The is_canceled API that users will use is defined in python/ray/runtime_context.py (code)\ndef is_canceled(self) -\u0026gt; bool: ... return self.worker.is_canceled Here, calling is_canceled from the self.worker will follow the code path (1 → 2 → 3) and eventually goes into CoreWorker::IsTaskCanceled. This is the place that we will check the task cancellation status.\nRecord the cancellation state # The cancel state can be put in either Python side or Cpp side, which is better?\nMy first proposal is to add a task context class on the Python side to record the task cancellation state (see here). However, this introduces a thread-safety issue: when multiple threads (e.g., one executing a callback and another running the actual actor task) access the shared cancellation flag simultaneously, a race condition can occur. To ensure thread safety and better performance, we should store the cancellation state in C++, utilizing C++ mutex or atomic variables (see here).\nThere are also different places that we can add is_canceled flag in C++ part:\nDirectly use is_canceled_ flag in TaskManager.\nthis cannot work as TaskManager runs in submitter side, and we want to get the is canceled status in the executor side Put in WorkerThreadContext(worker_context_) in HandleCancelTask (code)\nThis cannot work either. In executor, the place receiving RPC request and executing the task are in separate thread Execute task (main thread): code RPC request (spawned new thread): code Record the canceled task ID in the canceled_tasks_ hash set that\u0026rsquo;s shared between threads in the executor (code).\nThis is what we eventually do. When calling CoreWorker::CancelTaskOnExecutor, we will put the task ID into the set (code) When calling CoreWorker::IsTaskCanceled, we will check if the task ID is present in the canceled_tasks_ set (code) Raise TaskCanceled error # When async actor is canceled, it will raise asyncio.CancelledError, which is treated as an application error. In this case, when calling CompletePendingTask, it will raise TASK_CANCELLED error if it receives is_application_error to be true.\nHowever, when cancelling threaded actor, we will not raise any error, so the is_application_error will be false. In this case, we need to manually fail the actor task and raise the TASK_CANCELLED (as mentioned here).\nSee further information here: https://github.com/ray-project/ray/pull/58914/files#r2564220449\nSummary # This is my first Ray PR working on a feature and digging into the C++ side. It has been a pretty exciting experience, and I plan to keep contributing to Ray with more cool PRs ahead!\n","date":"27 December 2025","externalUrl":null,"permalink":"/posts/ray/ray-cancel-threaded-actor/","section":"Posts","summary":"Issue deep dive on how to support cancellation for threaded actor task","title":"Add support for cancelling threaded actor task","type":"posts"},{"content":"","date":"27 December 2025","externalUrl":null,"permalink":"/tags/ray/","section":"Tags","summary":"","title":"Ray","type":"tags"},{"content":"","date":"27 December 2025","externalUrl":null,"permalink":"/series/ray-issues/","section":"Series","summary":"","title":"Ray Issues","type":"series"},{"content":"","date":"23 August 2025","externalUrl":null,"permalink":"/tags/flyte/","section":"Tags","summary":"","title":"Flyte","type":"tags"},{"content":"Ever wondered how Flyte orchestrates complex workflows across distributed systems? This article breaks down Flyte\u0026rsquo;s core architecture, exploring how its components work together to transform your Python code into scalable, production-ready workflows.\nOverview # Flyte\u0026rsquo;s architecture consists of three logical planes that work together seamlessly, namely user, control, and data plane. For comprehensive details, see the official documentation.\nSimple Flyte Architecture Overview User Plane: Your interface to interact with the Flyte platform FlyteKit: Python SDK for defining workflows, tasks, and launch plans using decorators FlyteConsole: Web-based UI for visualizing workflows and monitoring executions FlyteCTL: Command-line tool for interacting with Flyte cluster from your terminal Control Plane: The brain of Flyte that processes user requests and manages workflow lifecycle FlyteAdmin: Central API server that validates inputs, compiles workflows into executable formats, and coordinates with the data plane Data Plane: The execution engine that runs workflows on Kubernetes and reports status back to the control plane FlytePropeller: Kubernetes controller that handles task reconciliation (ensuring actual state matches desired state) and invokes the appropriate FlytePlugin for task execution FlytePlugin: Extensible plugins that handle different task types by creating pods or invoking Kubernetes operators Flyte supports a wide range of plugins for various compute engines and cloud services, including Spark, Ray, PyTorch, Dask, AWS Batch, BigQuery, Snowflake, and many more. You can refer to all available plugins and their setup guide here Here\u0026rsquo;s how these components work together to execute a workflow:\nUser submits a workflow through FlyteKit, FlyteConsole, or FlyteCTL. FlyteAdmin validates the input, compiles the workflow, and forwards it to FlytePropeller. FlytePropeller selects the appropriate FlytePlugin to execute tasks and monitors progress until completion. Now let\u0026rsquo;s dive deeper into what happens during each step of workflow execution.\nWorkflow Execution # Before detailing the workflow execution, we briefly introduce three key Flyte concepts: launch plan, workflow, and task.\nLaunch plan: Template that defines inputs and configuration for the workflow Workflow: Collection of tasks organized into a complete pipeline Task: Individual unit of computation (e.g., data transformation, model training, etc.) We\u0026rsquo;ll discuss them in more detail in future articles.\nRegister and Execute Workflow The following steps illustrate how Flyte processes a workflow from client request to execution:\nClient requests launch plan: The client sends a getLaunchPlan request to FlyteAdmin. If no launch plan is explicitly set, a default launch plan is created with the same name as the workflow. FlyteAdmin returns launch plan: FlyteAdmin responds with the requested launch plan details. Client validates inputs: The client checks if all required inputs are provided based on the launch plan. Execution request submitted: The client sends a workflow execution request to FlyteAdmin. FlyteAdmin processes request: FlyteAdmin validates inputs and compiles the workflow and tasks. Metadata storage: The compiled workflow is uploaded to Flyte\u0026rsquo;s metadata storage (or fetched if previously compiled). Workflow translation: The compiled workflow is translated into a flyteworkflow custom resource (CR) with inputs. Custom Resource Definitions (CRDs) allow you to extend Kubernetes by defining your own resource types, similar to how built-in resources like Pod and Service are managed. A Custom Resource (CR) is an instance of such a type. Flyte uses this by defining a flyteworkflow CRD. FlytePropeller executes: FlytePropeller retrieves the flyteworkflow CR, invokes appropriate FlytePlugins for execution, and monitors execution status. Status updates: FlytePropeller continuously reports workflow status back to FlyteAdmin. These steps show how Flyte\u0026rsquo;s components work together seamlessly. From user request to workflow completion, each component plays a crucial role in ensuring reliable, scalable execution.\nSummary # Flyte\u0026rsquo;s three-plane architecture enables scalable workflow orchestration through clear separation of responsibilities:\nClient tools (FlyteKit, FlyteConsole, FlyteCTL): Your interface for defining, submitting, and monitoring workflows FlyteAdmin: Central control point that validates, compiles, and coordinates workflow execution FlytePropeller: Kubernetes controller that dispatch workflows and manages their lifecycle This architectural design ensures reliability, scalability, and maintainability for production-grade workflow orchestration.\n","date":"23 August 2025","externalUrl":null,"permalink":"/posts/flyte/flyte-architecture/","section":"Posts","summary":"Explore Flyte’s three-plane architecture and understand how user plane, control plane, and data plane work together to execute workflows reliably at scale.","title":"Flyte Architecture: How workflow runs","type":"posts"},{"content":"","date":"23 August 2025","externalUrl":null,"permalink":"/series/how-to-flyte/","section":"Series","summary":"","title":"How to Flyte","type":"series"},{"content":"","date":"18 August 2025","externalUrl":null,"permalink":"/","section":"Welcome to My Blog","summary":"","title":"Welcome to My Blog","type":"page"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"}]