Repository: spyder-ide/spyder

Issue:
Kernel fails to send config sometimes
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

### Issue Report Checklist

* [ ] Searched the [issues page](https://github.com/spyder-ide/spyder/issues?q=is%3Aissue) for similar reports
* [ ] Read the relevant sections of the [Spyder Troubleshooting Guide](https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ) and followed its advice
* [ ] Reproduced the issue after updating with ``conda update spyder`` (or ``pip``, if not using Anaconda)
* [ ] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [ ] Tried basic troubleshooting (if a bug/error)
    * [ ] Restarted Spyder
    * [ ] Reset preferences with ``spyder --reset``
    * [ ] Reinstalled the latest version of [Anaconda](https://www.anaconda.com/download/)
    * [ ] Tried the other applicable steps from the Troubleshooting Guide
* [ ] Completed the **Problem Description**, **Steps to Reproduce** and **Version** sections below


## Problem Description
The kernel is supposed to send the config when opening:

https://github.com/spyder-ide/spyder-kernels/blob/05476b35cf9e55787521c43f91dd5eedcb56c7a2/spyder_kernels/comms/frontendcomm.py#L183

But sometimes it doesn't! And it is known because I added this line:

https://github.com/spyder-ide/spyder-kernels/blob/05476b35cf9e55787521c43f91dd5eedcb56c7a2/spyder_kernels/comms/frontendcomm.py#L163

Which solves this exact problem.

I found a workaround in https://github.com/spyder-ide/spyder/pull/12134 that I could include in a standalone PR. But the problem remains: it should not be needed.



### What steps reproduce the problem?

1. The kernel connects to the comm but fails to send the configuration
2. The kernel sends a blocking request to the frontend (debugging / runfile / ...)
3. The frontend doesn't know the port to which the reply should be sent and the kernel is not listening to the shell channel (because it is waiting for a reply)

### What is the expected output? What do you see instead?

This causes a comm timeout error. I have no idea why the kernel fails to send the config. 

### Solutions
1 - Figure out why the config is not sent
2 - Always send the config with every message

## Versions
<!--- You can get this information from Help > About Spyder...
or (if Spyder won't launch) the "conda list" command
from the Anaconda Prompt/Terminal/command line. --->

* Spyder version: 
* Python version: 
* Qt version: 
* PyQt version: 
* Operating System name/version: 

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
PASTE DEPENDENCIES HERE
```



Discussion:
> I found a workaround in #12134 that I could include in a standalone PR

Please do, so I can include it for 4.1.4.

> But the problem remains: it should not be needed.

Perhaps things could be solved if we moved to use the control channel instead of our own (dedicated) commsn channel? I say it because that channel is present by default (which could be part of the issue, since we have to create our comms channel).
https://github.com/spyder-ide/spyder-kernels/pull/230
Thanks a lot @impact27!

Resolving patch:
diff --git a/external-deps/spyder-kernels/spyder_kernels/comms/frontendcomm.py b/external-deps/spyder-kernels/spyder_kernels/comms/frontendcomm.py
--- a/external-deps/spyder-kernels/spyder_kernels/comms/frontendcomm.py
+++ b/external-deps/spyder-kernels/spyder_kernels/comms/frontendcomm.py
@@ -154,13 +154,12 @@ def _wait_reply(self, call_id, call_name, timeout, retry=True):
         """Wait until the frontend replies to a request."""
         if call_id in self._reply_inbox:
             return
-
+        # Send config again just in case
+        self._send_comm_config()
         t_start = time.time()
         while call_id not in self._reply_inbox:
             if time.time() > t_start + timeout:
                 if retry:
-                    # Send config again just in case
-                    self._send_comm_config()
                     self._wait_reply(call_id, call_name, timeout, False)
                     return
                 raise TimeoutError(
diff --git a/spyder/plugins/ipythonconsole/widgets/client.py b/spyder/plugins/ipythonconsole/widgets/client.py
--- a/spyder/plugins/ipythonconsole/widgets/client.py
+++ b/spyder/plugins/ipythonconsole/widgets/client.py
@@ -265,6 +265,9 @@ def poll_stderr_file_change(self):
 
     def configure_shellwidget(self, give_focus=True):
         """Configure shellwidget after kernel is connected."""
+        # Make sure the kernel sends the comm config over
+        self.shellwidget.call_kernel()._send_comm_config()
+
         if give_focus:
             self.get_control().setFocus()
 


Test patch: