# ParaView Client/Server communication and abort support

**URL:** https://discourse.paraview.org/t/paraview-client-server-communication-and-abort-support/17430
**Category:** Development
**Created:** [February 5, 2026, 5:49pm UTC](https://discourse.paraview.org/t/paraview-client-server-communication-and-abort-support/17430 "2026-02-05T17:49:24Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![mwestphal](https://discourse.paraview.org/user_avatar/discourse.paraview.org/mwestphal/32/17_2.png) [@mwestphal](https://discourse.paraview.org/u/mwestphal)
#### Post date: [February 5, 2026, 5:49pm UTC](https://discourse.paraview.org/t/paraview-client-server-communication-and-abort-support/17430/1 "2026-02-05T17:49:25Z")

</div>

I’m currently working on supporting abort in ParaView and in that context I had to understand the client/server communication protocol, which is virtually undocumented even in developer docs.

So I decided to share my findings here and also share how I will actually adress aborting a filter in client/server mode.

Please note this is not the same as supporting asynchronous UI, which is another thing entirely, but is a step in that direction.

What happens when you press apply in client/server mode and there is no progress events:

```auto

        CLIENT SERVER               
          │ ┌─┐                
          │ │││                
          │ │││Receive()       
         ┌┴┐ ExecuteStream("UpdatePipeline") │││                
   Send()│├├──────────────────────────────────────────►└─┘                
         └┬┘ ┌─┐                
         ┌┴┐ │││                
   Send()│├├───────────────────────┐ │││                
         └┬┘ │ │││                
         ┌─┐ │ │││                
         │││ │ │││                
         │││ │ │││                
         │││ │ │││UpdatePipeline()
         │││ ExecuteStream("CleanupPendingProgress") │││                
         │││ │ │││                
         │││ │ │││                
         │││ │ │││                
         │││ │ │││                
         │││ │ │││                
         │││ │ │││                
         │││ │ └─┘                
         │││ └───────────────────►│                 
         │││ ┌─┐                
         │││ │││Cleanup()       
         │││ └─┘                
Receive()│││ CLEANUP_TAG ┌─┐                
         │││◄──────────────────────────────────────────┼┤│Send()          
         └─┘ └─┘                

```

As you can see, while the server is actually processing the data and doing the computation, the client is already trying to receive the CLEANUP\_TAG, and waits in that state until the server is sending it.

With ProgressEvent in between, here is how it looks:

```auto
                           CLIENT SERVER               
                             │ ┌─┐                
                             │ │││                
                             │ │││Receive()       
                            ┌┴┐ ExecuteStream("UpdatePipeline") │││                
                      Send()│├├──────────────────────────────────────────►└─┘                
                            └┬┘ ┌─┐                
                            ┌┴┐ │││                
                      Send()│├├───────────────────────┐ │││                
                            └┬┘ │ │││                
                            ┌─┐ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││UpdatePipeline()
                            │││ │ │││                
                   Receive()│││ │ │││                
   OnWrongTagEvent │││ PROGRESS_TAG 0.33 │││                
┌───────────────────────┐◄──│┘│◄──────────────────────┼───────────────────┼┤│                
│ RefreshProgress(0.33) │ │ │ │ │││                
└───────────────────────┴───►┐│ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
   OnWrongTagEvent Receive()│││ PROGRESS_TAG 0.66 │││                
┌───────────────────────┐◄──│┘│◄──────────────────────┬───────────────────┼┤│                
│ RefreshProgress(0.66) │ │ │ │ │││                
└───────────────────────┴───►┐│ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ ExecuteStream("CleanupPendingProgress") │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ │││                
                            │││ │ └─┘                
                            │││ └───────────────────►│                 
                            │││ ┌─┐                
                            │││ │││Cleanup()       
                            │││ └─┘                
                   Receive()│││ CLEANUP_TAG ┌─┐                
                            │││◄──────────────────────────────────────────┼┤│Send()          
                            └─┘ └─┘                

```

As you can see, the magic here is the `OnWrongTagEvent` Logic that let CLIENT receive the wrong message and execute code in reaction, before resuming the receive wait.

Given all of that, how do you fit a Abort logic in there.

For starters, we must stop the client for starting the cleanup progress stuff right away but instead wait for the completion of the pipeline before the cleanup.

Second we need a way for the client to inform the server that Abort was triggered.  
Adding a bidrectionnel OnWrongTagEvent may be possible but at this point an actual event queue would be prefferable and that is way too complex to set that up.

However, I can simply flag a proxy as aborted on client side and when processing a progress event, informing the server that a specific proxy have been aborted.

Here is how it looks:

```auto
                                                  CLIENT SERVER               
                                                    │ ┌─┐                
                                                    │ │││                
                                                    │ │││Receive()       
                                                   ┌┴┐ ExecuteStream("UpdatePipeline") │││                
                                             Send()│├├──────────────────────────────────────────►└─┘                
                                                   └─┘ ┌┬┐                
                                                   ┌─┐ │││                
                                                   │││ │││                
                                                   │││ │││                
                                                   │││ │││UpdatePipeline()
                                                   │││ │││                
                                          Receive()│││ │││                
                          OnWrongTagEvent │││ PROGRESS_T 0.33 │││                
                       ┌───────────────────────┐◄──│┘│◄──────────────────────────────────────────┼┤│                
                       │ RefreshProgress(0.33) │ │ │ ABORT FALSE │││                
                       └───────────────────────┴───►┌┼──────────────────────────────────────────►│││                
                                                   │││ │││                
                                                   │││ │││                
                                                   │││ │││                
                                                   │││ │││                
                                                   │││ │││                
                                                   │││ │││                
                          OnWrongTagEvent Receive()│││ PROGRESS_T 0.66 │││                
                       ┌───────────────────────┐◄──│┘│◄──────────────────────────────────────────┼┤│                
                       │ RefreshProgress(0.66) │ │ │ │││                
TriggerAbort()────────►│ Abort = true; │ │ │ ABORT TRUE │││                
                       └───────────────────────┴───►┌┼──────────────────────────────────────────►│││                
                                                   │││ └─┘                
                                          Receive()│││ STREAM_EXECUTED_TAG ┌┬┐                
                                                   │││◄──────────────────────────────────────────┼┤│Send()          
                                                   └┴┘ └┴┘                
                                                   ┌┬┐ ExecuteStream("CleanupPendingProgress") │                 
                                                   │├┼──────────────────────────────────────────►┌┼┐                
                                             Send()│││ │││                
                                                   └┴┘ │││Cleanup()       
                                                   ┌┬┐ └─┘                
                                                   │││ CLEANUP_TAG ┌─┐                
                                          Receive()│││◄──────────────────────────────────────────┼┤│Send()          
                                                   │││ └─┘                
                                                   └─┘                                                              

```

By waiting for `Receive(STREAM_EXECUTED_TAG)`, I ensure the socket stays free of clutter and can be used by the client to send a `ABORT` information back.

The `triggerAbort()` is a bit tricky and can be done thanks to Qt letting us input event during the `RefreshProgress` call, but improving this is a whole other subject.

I do not look specifcally for feedback here, but if you have any, feel free!

---

<div class="post-metadata">

### Author: ![mwestphal](https://discourse.paraview.org/user_avatar/discourse.paraview.org/mwestphal/32/17_2.png) [@mwestphal](https://discourse.paraview.org/u/mwestphal)
#### Post date: [February 17, 2026, 5:09pm UTC](https://discourse.paraview.org/t/paraview-client-server-communication-and-abort-support/17430/2 "2026-02-17T17:09:26Z")

</div>

Prototype here: [https://gitlab.kitware.com/paraview/paraview/-/merge\_requests/7664](https://gitlab.kitware.com/paraview/paraview/-/merge_requests/7664)

First MR here: [https://gitlab.kitware.com/paraview/paraview/-/merge\_requests/7700](https://gitlab.kitware.com/paraview/paraview/-/merge_requests/7700)

---

<div class="post-metadata">

### Author: ![mwestphal](https://discourse.paraview.org/user_avatar/discourse.paraview.org/mwestphal/32/17_2.png) [@mwestphal](https://discourse.paraview.org/u/mwestphal)
#### Post date: [August 21, 2026, 8:45am UTC](https://discourse.paraview.org/t/paraview-client-server-communication-and-abort-support/17430/3 "2026-08-21T08:45:21Z")

</div>

Follow ups since then:

- Abort button status: [https://gitlab.kitware.com/paraview/paraview/-/merge\_requests/7717](https://gitlab.kitware.com/paraview/paraview/-/merge_requests/7717)
- Add C/S abort support: [https://gitlab.kitware.com/paraview/paraview/-/merge\_requests/7725](https://gitlab.kitware.com/paraview/paraview/-/merge_requests/7725)
- Fix an issue with abort: [https://gitlab.kitware.com/paraview/paraview/-/merge\_requests/7913](https://gitlab.kitware.com/paraview/paraview/-/merge_requests/7913)
- FIx an issue with root only proxy: [https://gitlab.kitware.com/paraview/paraview/-/merge\_requests/7851](https://gitlab.kitware.com/paraview/paraview/-/merge_requests/7851)

I’ll soon post about how to abort in distributed client/server mode.
