Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build optimization true breaks SSE proxy requests in ng serve #21720

Closed
1 task done
ehealthexperts-rk opened this issue Sep 7, 2021 · 5 comments
Closed
1 task done

Comments

@ehealthexperts-rk
Copy link

🐞 Bug report

Command (mark with an x)

  • serve (best guess)

Is this a regression?

No.

Description

Due to another issue #20864 I accidentally turned on the optimization property projects.___.architect.build.options.optimization in angular.json. For reproduction it does not matter if the whole property is true or any of the more fine-grained options scripts/styles.minify/fonts is true:

"optimization": {
	  "scripts": true,
	  "styles": {
		"minify": true,
		"inlineCritical": false
	  },
	  "fonts": true
	}

Besides I use a proxy configuration to get data from the backend:

{
  "/rest": {
    "target": "https://localhost:9000",
    "changeOrigin": true,
    "secure": false,
    "logLevel": "debug",
    "timeout": 3600000
  }
}

If above optimization is active the server in dev-mode starts with a big red banner:

****************************************************************************************
This is a simple server for use in testing or debugging Angular applications locally.
It hasn't been reviewed for security issues.

DON'T USE IT FOR PRODUCTION!
****************************************************************************************

The regular rest endpoints work normally with this.
One special endpoint that emit server sent events is failing though. The browser connects and holds the connection but the events are not received by the EventSource in the browser anymore. The reason seems to be that activated compression does not work with SSE.
I can reproduce the behavior with curl when I activate the --compressed option:

works: curl 'http://localhost:4200/rest/events' -H 'Accept: text/event-stream' -H 'Connection: keep-alive' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'
fails: curl 'http://localhost:4200/rest/events' -H 'Accept: text/event-stream' --compressed -H 'Connection: keep-alive' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'

I do not know which component/library should handle the issue that compression does not work well with SSE. As a user of angular it took me some hours to pin the problem.
Maybe the same issue from a different project: chimurai/http-proxy-middleware#371

🔬 Minimal Reproduction

  • in angular.json set projects.mgmt-gui.architect.build.options.optimization to true
  • start the app with ng serve
  • in the app you need to use "new EventSource(url-to-backend)"
  • activate a proxy-config to redirect request to your backend on another port
  • have and start a backend that emit server sent events
  • as example my java/spring SseController looks like:
package com.example;

import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import de.ehex.connector.basic.event.EventService;
import de.ehex.connector.mgmt.rest.RestConstants;

@Controller
@PreAuthorize(RestConstants.AUTH_ANY_ADMIN)
@RequestMapping(RestConstants.ANWENDUNGS_KONNEKTOR_BASEURL + "/ereignisse")
public class SseController {

  private static final Logger LOG = LoggerFactory.getLogger(SseController.class);

  private final CopyOnWriteArrayList<SseEmitter> emitters = new CopyOnWriteArrayList<>();

  @Autowired
  private EventService eventService;

  @Autowired
  private TaskScheduler scheduler;

  @PostConstruct
  public void init() {
    this.scheduler.scheduleAtFixedRate(this::sendTime, Instant.now(), Duration.ofSeconds(1));
  }

  @PreDestroy
  public void destroy() {
    try {
      this.emitters.forEach(e -> e.complete());
    } catch (final RuntimeException e) {
      this.emitters.clear();
    }
  }

  @RequestMapping(method = RequestMethod.GET, produces = { MediaType.TEXT_EVENT_STREAM_VALUE })
  public SseEmitter handle() {
    final SseEmitter emitter = new SseEmitter(600_000l);
    this.emitters.add(emitter);

    emitter.onCompletion(() -> {
      this.emitters.remove(emitter);
    });
    emitter.onTimeout(() -> {
      this.emitters.remove(emitter);
    });
    return emitter;
  }

  public void sendTime() {
    if (this.emitters.isEmpty()) {
      return;
    }

    String msg = Instant.now().toString();
    LOG.debug("sending msg to {} subscriber: {}", this.emitters.size(), msg);
    final List<SseEmitter> deadEmitters = new ArrayList<>();
    this.emitters.forEach(emitter -> {
      try {
        emitter.send(msg);
      } catch (final IOException e) {
        deadEmitters.add(emitter);
      }
    });

    this.emitters.removeAll(deadEmitters);
  }
}

🔥 Exception or Error

No exceptions, not even in debug log of the proxy-config.

🌍 Your Environment


     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 12.2.4
Node: 14.16.0
Package Manager: npm 6.14.11
OS: linux x64

Angular: 12.2.4
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1202.4
@angular-devkit/build-angular   12.2.4
@angular-devkit/core            12.2.4
@angular-devkit/schematics      12.2.4
@schematics/angular             12.2.4
rxjs                            6.6.3
typescript                      4.3.5
   

Anything else relevant?

No.

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Sep 7, 2021

@ehealthexperts-rk
Copy link
Author

Yes, exactly, thank you!

I set

  • optimization: true in both projects.___.architect.build.options.optimization and projects.___.architect.build.configurations.production.optimization and
  • hardcoded devServer.compress to false in node_modules/@angular-devkit/build-angular/src/webpack/configs/dev-server.js

and still receive SSE in the app.

Not sure how a fix could look like. Compression in general makes sense for optimized styles and scripts. Somehow compression/chunking must be blocked on a per request basis, maybe configurably and defaulting to text/event-stream. Maybe rather an issue in the devServer.

@alan-agius4
Copy link
Collaborator

Compression isn't particular useful during development, also in version 13 we disable this completely. I'll open a PR to back-port this.

@alan-agius4 alan-agius4 added freq1: low Only reported by a handful of users who observe it rarely severity3: broken type: bug/fix and removed needs: more info Reporter must clarify the issue labels Sep 8, 2021
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Sep 8, 2021
@alan-agius4
Copy link
Collaborator

Closed via #21723

alan-agius4 added a commit that referenced this issue Sep 8, 2021
…ession

Compression isn't particular useful during development, also in version 13 we disable this completely due to timeouts issues which it causes.

This backports this change which also addresses another issues as described here #21720

Closes #21720
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Oct 9, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants