Repository: bentoml/BentoML

Issue:
`--reload` is not supported on Windows
**Describe the bug**
<!--- A clear and concise description of what the bug is. -->

In QuickStart guide, calling `bentoml serve --reload` will throw error:
```
NotImplementedError: Streams are not supported on Windows.
```


**To Reproduce**
<!--
Steps to reproduce the issue:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
Run QuickStart python notebook in the gallery project, at the serving command cell `bentoml serve service.py:svc --reload` it will throw error:
```

+--------------------- Traceback (most recent call last) ---------------------+
| C:\ProgramData\Anaconda3\lib\runpy.py:197 in _run_module_as_main            |
|                                                                             |
|   194     main_globals = sys.modules["__main__"].__dict__                   |
|   195     if alter_argv:                                                    |
|   196         sys.argv[0] = mod_spec.origin                                 |
| > 197     return _run_code(code, main_globals, None,                        |
|   198                      "__main__", mod_spec)                            |
|   199                                                                       |
|   200 def run_module(mod_name, init_globals=None,                           |
|                                                                             |
| C:\ProgramData\Anaconda3\lib\runpy.py:87 in _run_code                       |
|                                                                             |
|    84                        __loader__ = loader,                           |
|    85                        __package__ = pkg_name,                        |
|    86                        __spec__ = mod_spec)                           |
| >  87     exec(code, run_globals)                                           |
|    88     return run_globals                                                |
|    89                                                                       |
|    90 def _run_module_code(code, init_globals=None,                         |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\Scripts\bentoml.exe\__main__ |
| .py:7 in <module>                                                           |
|                                                                             |
| [Errno 2] No such file or directory: 'C:\\Users\\hwang\\AppData\\Roaming\\P |
| ython\\Python39\\Scripts\\bentoml.exe\\__main__.py'                         |
|                                                                             |
| C:\ProgramData\Anaconda3\lib\site-packages\click\core.py:1128 in __call__   |
|                                                                             |
| C:\ProgramData\Anaconda3\lib\site-packages\click\core.py:1053 in main       |
|                                                                             |
| C:\ProgramData\Anaconda3\lib\site-packages\click\core.py:1659 in invoke     |
|                                                                             |
| C:\ProgramData\Anaconda3\lib\site-packages\click\core.py:1395 in invoke     |
|                                                                             |
| C:\ProgramData\Anaconda3\lib\site-packages\click\core.py:754 in invoke      |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\bentoml\_inter |
| nal\cli\click_utils.py:167 in wrapper                                       |
|                                                                             |
|   164         @functools.wraps(func)                                        |
|   165         def wrapper(*args: "P.args", **kwargs: "P.kwargs") -> t.Any:  |
|   166             try:                                                      |
| > 167                 return func(*args, **kwargs)                          |
|   168             except BentoMLException as err:                           |
|   169                 msg = f"[{cmd_group.name}] `{command_name}` failed: { |
|   170                 raise ClickException(click.style(msg, fg="red")) from |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\bentoml\_inter |
| nal\cli\click_utils.py:139 in wrapper                                       |
|                                                                             |
|   136                     )                                                 |
|   137                                                                       |
|   138             try:                                                      |
| > 139                 return_value = func(*args, **kwargs)                  |
|   140                 event = get_tracking_event(return_value)              |
|   141                 duration_in_ns = time.time_ns() - start_time          |
|   142                 event.duration_in_ms = duration_in_ns / 1e6           |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\bentoml\_inter |
| nal\cli\click_utils.py:101 in wrapper                                       |
|                                                                             |
|    98                                                                       |
|    99             configure_logging()                                       |
|   100                                                                       |
| > 101             return func(*args, **kwargs)                              |
|   102                                                                       |
|   103         return wrapper                                                |
|   104                                                                       |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\bentoml\_inter |
| nal\cli\bento_server.py:146 in serve                                        |
|                                                                             |
|   143         else:                                                         |
|   144             from ..server import serve_development                    |
|   145                                                                       |
| > 146             serve_development(                                        |
|   147                 bento,                                                |
|   148                 working_dir=working_dir,                              |
|   149                 with_ngrok=run_with_ngrok,                            |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\simple_di\__in |
| it__.py:139 in _                                                            |
|                                                                             |
|   136         bind = sig.bind_partial(*filtered_args, **filtered_kwargs)    |
|   137         bind.apply_defaults()                                         |
|   138                                                                       |
| > 139         return func(*_inject_args(bind.args), **_inject_kwargs(bind.k |
|   140                                                                       |
|   141     setattr(_, "_is_injected", True)                                  |
|   142     return cast(WrappedCallable, _)                                   |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\bentoml\_inter |
| nal\server\__init__.py:122 in serve_development                             |
|                                                                             |
|   119     else:                                                             |
|   120         plugins = []                                                  |
|   121                                                                       |
| > 122     arbiter = create_standalone_arbiter(                              |
|   123         watchers,                                                     |
|   124         sockets=circus_sockets,                                       |
|   125         plugins=plugins,                                              |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\bentoml\_inter |
| nal\utils\circus.py:56 in create_standalone_arbiter                         |
|                                                                             |
|    53                                                                       |
|    54     with reserve_free_port() as endpoint_port:                        |
|    55         with reserve_free_port() as pubsub_port:                      |
| >  56             return Arbiter(                                           |
|    57                 watchers,                                             |
|    58                 endpoint=f"tcp://127.0.0.1:{endpoint_port}",          |
|    59                 pubsub_endpoint=f"tcp://127.0.0.1:{pubsub_port}",     |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\circus\arbiter |
| .py:232 in __init__                                                         |
|                                                                             |
|   229                 if 'name' not in plugin_cfg:                          |
|   230                     plugin_cfg['name'] = fqn                          |
|   231                                                                       |
| > 232                 plugin_watcher = Watcher.load_from_config(plugin_cfg) |
|   233                 self.watchers.append(plugin_watcher)                  |
|   234                                                                       |
|   235         self.sockets = CircusSockets(sockets)                         |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\circus\watcher |
| .py:407 in load_from_config                                                 |
|                                                                             |
|    404             config['env'] = parse_env_dict(config['env'])            |
|    405         cfg = config.copy()                                          |
|    406                                                                      |
| >  407         w = cls(name=config.pop('name'), cmd=config.pop('cmd'), **co |
|    408         w._cfg = cfg                                                 |
|    409                                                                      |
|    410         return w                                                     |
|                                                                             |
| C:\Users\hwang\AppData\Roaming\Python\Python39\site-packages\circus\watcher |
| .py:253 in __init__                                                         |
|                                                                             |
|    250                                                                      |
|    251         if IS_WINDOWS:                                               |
|    252             if self.stdout_stream or self.stderr_stream:             |
| >  253                 raise NotImplementedError("Streams are not supported |
|    254                                           " on Windows.")            |
|    255                                                                      |
|    256             if not copy_env and not env:                             |
+-----------------------------------------------------------------------------+
NotImplementedError: Streams are not supported on Windows.
```


**Expected behavior**
<!--- A clear and concise description of what you expected to happen. -->

**Screenshots/Logs**
<!--- 
If applicable, add screenshots, logs or error outputs to help explain your problem.

To give us more information for diagnosing the issue, make sure to enable debug logging:

Enable via environment variable, e.g.:
```
$ git clone git@github.com:bentoml/BentoML.git && cd bentoml
$ BENTOML_DEBUG=TRUE python guides/quick-start/main.py
```

Or set debug logging in your Python code:
```python
from bentoml.configuration import set_debug_mode
set_debug_mode(True)
```

For BentoML CLI commands, simply add the `--verbose` flag, e.g.:
```bash
bentoml get IrisClassifier --verbose
```

-->


**Environment:**
 - OS: Windows
 - Python Version 3.9
 - BentoML Version 1.0.0rc3


**Additional context**
<!-- Add any other context about the problem here. e.g. links to related discussion. -->
Slack conversation link: https://bentoml.slack.com/archives/CKRANBHPH/p1656746500464369


Discussion:
@bojiang this has to do with circus on windows?
Hello, all,
Do you have a chance to take a look? Is there any way to avoid this issue? 
I believe this has to do with how circus doesn't have full support for windows.
I believe that `--reload` is not supported on Windows. @hwang250. 
Thanks, @aarnphm. Yes, it works without --reload option for windows.
 
Looks that, it would be helpful if an error msg is updated in this case instead of using "NotImplementedError: Streams are not supported on Windows" 
added #2707 

Resolving patch:
diff --git a/bentoml/_internal/server/__init__.py b/bentoml/_internal/server/__init__.py
--- a/bentoml/_internal/server/__init__.py
+++ b/bentoml/_internal/server/__init__.py
@@ -106,12 +106,16 @@ def serve_development(
                 "bentoml_home": bentoml_home,
             },
         ]
+    if sys.platform == "win32":
+        logger.warning(
+            "Due to circus limitations, output from reloader plugin will not be shown on Windows."
+        )
 
     arbiter = create_standalone_arbiter(
         watchers,
         sockets=circus_sockets,
         plugins=plugins,
-        debug=True,
+        debug=True if sys.platform != "win32" else False,
     )
     ensure_prometheus_dir()
 


Test patch: