Server-sent live updates: protocol and reference implementation

Mercure: Real-time Made Easy

Protocol and Reference Implementation

Mercure is a protocol allowing to push data updates to web browsers and other HTTP clients in a convenient, fast, reliable and battery-efficient way. It is especially useful to publish async and real-time updates of resources served through web APIs, to reactive web and mobile apps.

Awesome PkgGoDev CI Coverage Status Go Report Card

Subscriptions Schema

The protocol has been published as an Internet Draft that is maintained in this repository.

A reference, production-grade, implementation of a Mercure hub (the server) is also available in this repository. It's a free software (AGPL) written in Go. It is provided along with a library that can be used in any Go application to implement the Mercure protocol directly (without a hub) and an official Docker image.

In addition, a managed and high-scalability version of the Mercure.rocks hub is available on Mercure.rocks.

Contributing

See CONTRIBUTING.md.

License and Copyright

See https://mercure.rocks/docs/hub/license.

Credits

Created by Kévin Dunglas. Graphic design by Laury Sorriaux. Sponsored by Les-Tilleuls.coop.

Owner
Kévin Dunglas
Founder of @coopTilleuls / Creator of @api-platform, Mercure.rocks and Vulcain.rocks / @symfony Core Team
Kévin Dunglas
Comments
  • Offer more debug on infamous 401

    Offer more debug on infamous 401

    Hey,

    after sorting out the CORS issue with anonymous request, I'm trying to use authorized ones, but the 401 is driving me nuts. I'm running on a my.test domain and mercure is running on my.test:3000. It somehow seems that the browser doesn't want to send the cookie along with the EventSource. At least it cannot be found in the Request Headers section in the dev tools.

    The cookie is created through a Symfony action:

    Set-Cookie: mercureAuthorization=...; path=/hub; httponly; samesite=strict

    and I can verify it on jwt.io.

    1. I tried to use withCredentials: true on the EventSource, but than the browser complains that * is not allowed in the CORS_ALLOWED_ORIGINS.

    2. I then tried to use CORS_ALLOWED_ORIGINS=http://localhost, but then Chrome complains that "No 'Access-Control-Allow-Origin' header is present" and the network tab shows no response headers at all.

    3. I then set CORS_ALLOWED_ORIGINS=http://my.test. This way I get a proper Access-Control-Allow-Origin: http://my.test response header, but along with the 401 and no cookie in the request headers.

    4. If I access http://my.test:3000/hub?topic=... directly the cookie is properly sent.

    So... what setup should? Should the same-site cookie be send with EventSource w/o credentials? Should it work with CORS_ALLOWED_ORIGINS=*?

    And pleeease add a reason for the 401 when running with DEBUG=1. There are so many different things which can go wrong and mercure has to know what it doesn't like.

    Cheers Matthias

  • Subscription API causes memory overshoot

    Subscription API causes memory overshoot

    Hi. I'm using Mercure's official docker image with a few customizations in Caddyfile. Without the subscription API turned on, the memory usage is very low. But as soon as I enable the subscription API, the memory usage jumps to 100% and the container crashes. Container and load specs are as follows:

    CPU units: ~680 (t3a.medium EC2 instance, 2 vCPUs, shared by one Mercure task with two other tasks) Memory: 256 Subscribers: ~50 Topics: ~5 Messages: 5/minute (avg)

    The memory graph attached shows the memory used when subscription API is enabled and when it's disabled. From 10:05 to 11:45 is the time when subscription API is disabled. From 07:00 to 10:00 and from 11:45 onwards are the windows when subscription API is enabled. The dips you see in those windows are actually crashes, not low memory usages. The memory consupmtion is constantly 100% when the container is running.

    Mercure memory

    Unfortunately there's nothing in cloudwatch logs before the crash happens, and the reason for task being stopped in ECS console (strangely enough) is not out of memory. It says that the essential container in task exited.

  • is CORS broken?

    is CORS broken?

    Trying to setup mercure with cors, but I can't seem to get it to work.

    Think it's been like that for a while, since #442 has been closed with wontfix by a stale bot we'd have to keep opening issues? or get some understanding in the issue

    Using this caddyfile with the docker image:

    # Learn how to configure the Mercure.rocks Hub on https://mercure.rocks/docs/hub/config
    {
        # Debug mode (disable it in production!)
        {$DEBUG:debug}
        # HTTP/3 support
        servers {
            protocol {
                experimental_http3
            }
        }
    }
    
    {$SERVER_NAME:localhost}
    
    log
    
    route {
        redir / /.well-known/mercure/ui/
        encode zstd gzip
    
        mercure {
            # Transport to use (default to Bolt)
            transport_url {$MERCURE_TRANSPORT_URL:bolt://mercure.db}
            # Publisher JWT key
            publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
            # Subscriber JWT key
            subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
            # Permissive configuration for the development environment
            cors_origins http://votes.wolbodo/
            publish_origins *
            demo
            anonymous
            subscriptions
            # Extra directives
            {$MERCURE_EXTRA_DIRECTIVES}
        }
    
        respond /healthz 200
    
        respond "Not Found" 404
    }
    
  • No 'Access-Control-Allow-Origin' header is present on the requested resource

    No 'Access-Control-Allow-Origin' header is present on the requested resource

    I've just moved over from the legacy to the new Caddy version and getting has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    Is this an issue with the cors on the mercure server side or is it something to do with the requesting server not sending the correct header. Currently its hosted on an nginx docker and uses Cloudflare for dns routing

    {"level":"info","ts":1610116467.3811321,"logger":"http.log.access","msg":"handled request","request":{"remote_addr":"188.114.110.34:29984","proto":"HTTP/1.1","method":"GET","host":"XXXXXXXXX:8443","uri":"/.well-known/mercure?topic=https%3A%2F%2FXXXXXXXXX%2Fv1%2Fmanage%2Fcontacts%2F4311","headers":{"Cf-Request-Id":["078404a26b0000ff6867993000000001"],"Cdn-Loop":["cloudflare"],"Origin":["https://192.168.1.170"],"Referer":["https://192.168.1.170/"],"Accept-Language":["en-GB,en-US;q=0.9,en;q=0.8,nl;q=0.7"],"Sec-Fetch-Site":["cross-site"],"Cf-Connecting-Ip":["86.134.113.95"],"X-Forwarded-Proto":["https"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Accept":["text/event-stream"],"Cache-Control":["no-cache"],"User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4356.6 Safari/537.36"],"Sec-Fetch-Mode":["cors"],"Sec-Fetch-Dest":["empty"],"Connection":["Keep-Alive"],"Accept-Encoding":["gzip"],"X-Forwarded-For":["86.134.113.95"],"Cf-Ipcountry":["GB"],"Cf-Ray":["60e6a3b0ad41ff68-MAD"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"XXXXXXXXX"}},"common_log":"188.114.110.34 - - [08/Jan/2021:14:34:27 +0000] \"GET /.well-known/mercure?topic=https%3A%2F%2FXXXXXXXXX%2Fv1%2Fmanage%2Fcontacts%2F4311 HTTP/1.1\" 0 0","duration":0.00000684,"size":0,"status":0,"resp_headers":{"Server":["Caddy"],"Alt-Svc":["h3-32=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000"]}}

  • Mercure Hub not automatically pushing updates

    Mercure Hub not automatically pushing updates

    I have a quick test Symfony application running to try to integrate the Mercure protocol.

    I have a test Mercure hub running with the following:

    JWT_KEY='aVerySecretKey' ADDR='localhost:3000' ALLOW_ANONYMOUS=1 CORS_ALLOWED_ORIGINS=* ./mercure
    

    I have a form that submits the data to the following endpoint:

         /**
         * @Route("/resources", name="resourcesPost", methods={"POST"})
         */
        public function resourcesPost(Publisher $publisher, Request $request){
    
            $user = $this->getUser();
    
            $update = new Update(
                'http://example.com/books/1',
                json_encode([
                    'from' => $user->getFullName(),
                    'sent at' => (new DateTime())->format('H:i:s'),
                    'message' => $request->request->get('message'),
                ])
            );
    
            $publisher($update);
    
            return $this->redirectToRoute('resources');
        }
    

    Once I hit the form I get the following in the debugger:

    127.0.0.1 - - [19/Jun/2019:13:27:40 -0400] "GET /hub?topic=http%3A%2F%2Fexample.com%2Fbooks%2F1&topic=http%3A%2F%2Fexample.com%2Fbooks%2F2&topic=http%3A%2F%2Fexample.com%2Freviews%2F%7Bid%7D HTTP/1.1" 200 31 "http://localhost:8888/resources" "Mozilla/5.0 (Windows N
    T 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0"
    time="2019-06-19T13:32:50-04:00" level=info msg="Subscriber disconnected" remote_addr="127.0.0.1:65391"
    time="2019-06-19T13:32:53-04:00" level=info msg="Update published" event_id=cd3acff1-7e9b-4e28-b6ba-e79aeb4c1791 remote_addr="127.0.0.1:49546"
    127.0.0.1 - - [19/Jun/2019:13:32:53 -0400] "POST /hub HTTP/1.0" 200 36 "" ""
    time="2019-06-19T13:32:53-04:00" level=info msg="Event sent" event_id=cd3acff1-7e9b-4e28-b6ba-e79aeb4c1791 remote_addr="127.0.0.1:65384"
    

    However, the javascript on the second browser that is listening, does not put the response in the console log :

      const u = new URL('http://localhost:3000/hub');
      u.searchParams.append('topic', 'http://example.com/books/1');
      // Subscribe to updates of several Book resources
      u.searchParams.append('topic', 'http://example.com/books/2');
      // All Review resources will match this pattern
      u.searchParams.append('topic', 'http://example.com/reviews/{id}');
       
      const es = new EventSource(u);
      let lastEventId = null;
      es.onmessage = e => {
           let data = JSON.parse(e.data);
           lastEventId = e.lastEventId;
           console.log(data);
      }
    

    If I go into the back into the terminal and run ctrl+c (to kill the Mercure server) the data will then get pushed into the javascript. My question is how do I get it to automatically push the data to the javascript without having to kill the Mercure server (running on localhost:3000) and then restart it?

  • [leak] High CPU usage with a lot of subscribers

    [leak] High CPU usage with a lot of subscribers

    Hello,

    This issue has been created to track down the problem that I'm having with Mercure:

    Mercure uses almost %100 CPU, doesn't matter what specs you've.

    The reason is probably a lot of subscribers and updates published to them:

    # TYPE mercure_subscribers gauge
    mercure_subscribers 4299
    # HELP mercure_subscribers_total Total number of handled subscribers
    # TYPE mercure_subscribers_total counter
    mercure_subscribers_total 2.939146e+06
    # HELP mercure_updates_total Total number of handled updates
    # TYPE mercure_updates_total counter
    mercure_updates_total 7.891176e+06
    

    This is just for 2 days, this is a reduced amount, normally it's up to x4 of updates that are currently disabled.

    Here is debug profile of CPU:

    File: caddy
    Type: cpu
    Time: Aug 26, 2021 at 6:53am
    Duration: 300.16s, Total samples = 461.92s (153.89%)
    Entering interactive mode (type "help" for commands, "o" for options)
    (pprof) top
    Showing nodes accounting for 231.78s, 50.18% of 461.92s total
    Dropped 1620 nodes (cum <= 2.31s)
    Showing top 10 nodes out of 141
          flat  flat%   sum%        cum   cum%
        55.77s 12.07% 12.07%    191.39s 41.43%  runtime.selectgo
        41.19s  8.92% 20.99%     52.73s 11.42%  runtime.sellock
        24.36s  5.27% 26.26%     24.40s  5.28%  runtime.(*waitq).dequeue (inline)
        22.55s  4.88% 31.15%    114.28s 24.74%  github.com/dunglas/mercure.(*Subscriber).CanDispatch
        18.83s  4.08% 35.22%     18.83s  4.08%  go.uber.org/zap.(*Logger).check
        16.90s  3.66% 38.88%     17.25s  3.73%  runtime.unlock2
        14.31s  3.10% 41.98%     32.20s  6.97%  github.com/dunglas/mercure.canReceive
        13.21s  2.86% 44.84%     13.21s  2.86%  runtime.empty
        12.48s  2.70% 47.54%     44.65s  9.67%  runtime.schedule
        12.18s  2.64% 50.18%     12.64s  2.74%  runtime.gopark
    

    pprof.caddy.samples.cpu.006.pb.gz

    Here is the image of it: dump1

    The problematic lines are:

    https://github.com/dunglas/mercure/blob/ca2df66f27356aa2511ef4f959fc4156a0f69a94/subscriber.go#L68-L102

    At first, we thought the problem is with Zap(*Logger) check but PR https://github.com/dunglas/mercure/pull/554 should fix it.

    Anyways, completely removing Zap logging, the situation didn't improve but instead showed more problems with runtime.selectgo

    Here is debug profile of CPU:

    File: caddy
    Type: cpu
    Time: Aug 31, 2021 at 12:27pm
    Duration: 300.10s, Total samples = 568.67s (189.49%)
    Entering interactive mode (type "help" for commands, "o" for options)
    (pprof) top
    Showing nodes accounting for 347.87s, 61.17% of 568.67s total
    Dropped 1614 nodes (cum <= 2.84s)
    Showing top 10 nodes out of 116
          flat  flat%   sum%        cum   cum%
        76.58s 13.47% 13.47%    263.92s 46.41%  runtime.selectgo
        50.10s  8.81% 22.28%     50.28s  8.84%  runtime.(*waitq).dequeue (inline)
        47.13s  8.29% 30.56%     59.44s 10.45%  runtime.sellock
        29.29s  5.15% 35.71%     29.29s  5.15%  memeqbody
        29.05s  5.11% 40.82%     86.37s 15.19%  github.com/dunglas/mercure.(*Subscriber).CanDispatch
        28.25s  4.97% 45.79%    166.05s 29.20%  github.com/dunglas/mercure.(*Subscriber).Dispatch
        25.76s  4.53% 50.32%     57.32s 10.08%  github.com/dunglas/mercure.canReceive
        25.14s  4.42% 54.74%     25.14s  4.42%  runtime.empty (inline)
        18.58s  3.27% 58.01%     19.21s  3.38%  runtime.gopark
        17.99s  3.16% 61.17%     17.99s  3.16%  runtime.(*gQueue).pop
    

    Here is the image of it: dump2

    Sorry, I can't write a benchmark for it but ready to test what changes is needed.

    Data posted to Mercure is always to different topics.

    Posted to topics: /users/613193cee6be0e1016042334

    Private: true

    Data:

    {
    	"@context": "/contexts/User",
    	"@id": "/users/613193cee6be0e1016042334",
    	"@type": "User",
    	"id": "613193cee6be0e1016042334",
    	"quota": 40000,
    	"used": 7186,
    	"isDisabled": false,
    	"isDeleted": false,
    	"createdAt": "2021-09-03T05:17:34+02:00",
    	"updatedAt": "2021-09-03T05:18:29+02:00"
    }
    

    Thanks!

  • Subscription events not working?

    Subscription events not working?

    Hi @dunglas ,

    thank you for your update so we can use subscription events. I cloned the branch and built the hub so I can use the functionality but it seems not to work. Whenever I subscribe the following event:

    https://mercure.rocks/targets/subscriptions
    

    I never get a subscription event as you wrote in the documentation. I also added several log outputs to be sure that the specific code will be called. And yes, it is called. But I never get the message back to my application.

    Here is what I use:

    var url = new URL('my-hub-url');
    url.searchParams.append('topic', 'https://mercure.rocks/targets/subscriptions');
    
    var eventSource = new EventSourcePolyfill(url);
    eventSource.onmessage = this.onMessage.bind(this);
    eventSource.onerror = this.onError.bind(this);
    eventSource.onopen = this.onOpen.bind(this);
    
    // Example message method (works in my application) but is never 
    // called when a new user connects
    onMessage: function(e) {
        console.log({ e });
    }
    

    The onMessage -method is called when I send updates to the hub. But never when a new user connects to the hub. Maybe I am doing something wrong and you can provide me a tip? Or isn't it implemented completely?

  • Memory leaking

    Memory leaking

    Hello!

    I am observing strange mercure behaviour. It has around 1000 or less subscribers but it seems that memory consumption increases gradually until it eats up all available memory. Then processor usage sky-rocket and situation does not improve until restarted.

    Zabix screenshot

    I started from 1 core and 2 gigs of ram. Then upped to 2 cores and 4 gigs. Now it runs on 2 cores and 8 gigs of ram. Behaviour seems repeat no matter the amount of ram we give it.

    After restart situation gets back to normal.

    Zabix screenshot

    I'm running official docker installation dunglas/mercure:v0.10.4

    What should be expected memory usage? What can be done to debug the situation?

  • Error net::ERR_SPDY_PROTOCOL_ERROR

    Error net::ERR_SPDY_PROTOCOL_ERROR

    I'm trying to use mercure in GCE kubernetes cluster with existing API platform setup and I've started to get network errors for subscribers every 30 seconds when moved from localhost to cluster. The error is:

    GET https://mercure.example.com/hub?topic=https%3A%2F%2Fmercure.example.com%2Fhub%2Ftest%2F1 net::ERR_SPDY_PROTOCOL_ERROR 200

    I'm attaching chrome development tools print screen for better clarification: mercure-debug

    My subscriber html script is:

    Otherwise publishing works just fine and subscriber is notified, only the constant network errors remain the problem.

    I also set the heartbeatInterval: 15s but it doesn't prevent the error.

    Another thing to note is that is that we are using gce ingress which forwards subscriber traffic directly to mercure service.

    Any help would be appreciated :)

  • Improve telemetry

    Improve telemetry

    This PR exposes the telemetry endpoint under a new address (as suggested in #242). It's supposed to deprecate the previous "metrics" configuration and endpoints.

    In the kubernetes world (but IMHO in other places too) telemetry information should not be exposed to the whole world. Mercure currently provides authentication support, but exposing telemetry on a separate port, closed from public access is IMHO better.

    This is a first version demonstrating the feature. It lacks the authentication support requested by @dunglas in https://github.com/dunglas/mercure/issues/242#issuecomment-664368534, but since it's on a different port, I doubt builtin authentication will actually be useful. I'd probably suggest in the documentation to setup a proxy with authentication if it's absolutely necessary. Putting credentials in a config file is not secure anyway. That being said, I can add authentication support if you still think it's necessary.

    Ideally, the "old" metrics endpoint should be deprecated and removed at some point. If you are not concerned with backwards compatibility, I can remove it in this PR (or a separate one). I would also make telemetry enabled by default.

    I also added the healthz endpoint to the telemetry address. I would use this endpoint as the liveness check in Kubernetes.

    This PR also requires some changes in the Helm chart, but before adding changes there, I'd love to discuss #357.

  • [Symfony] Can't get mercure to work

    [Symfony] Can't get mercure to work

    I am trying to set up mercure with symfony, but no matter what i change, it always results in "Failed to send an update." ("MERCUR Topic selectors not matched, not provided or authorization error" in the Server logs).

    I installed mercure via "composer req mercure" and start the server via "symfony server:run --allow-http", as dunglas/mercure#485 states that https will lead to problems. I also tried with "php -S localhost:8000" and starting the mercury binary manually, but no working results.

    Environment Variables:

    MERCURE_URL=http://localhost:3000/.well-known/mercure
    MERCURE_PUBLIC_URL=http://localhost:3000/.well-known/mercure
    MERCURE_PUBLISH_URL=http://localhost:3000/.well-known/mercure
    MERCURE_JWT_SECRET=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdfX0.oIy5_VUByd4lbCh6IcntwdiM2oyZ2gbrSp1jhcWz3tU
    

    The secret was generated with https://jwt.io/, using "aaaaaaaa" as a key.

    Interestingly, mercure seems to start on port 8000, as I'm getting "Missing "topic" parameter." if i visit localhost:8000/.well-known/mercure

    I tried setting the port to 8000, but this doesn't work either. Also, changing http to https doesn't work.

    Call in Symfony Controller:

    $update = new Update(
      '/entries',
      json_encode(['message' => 'heyo']),
    );
    $hub->publish($update);
    
  • Dead link in documentation / Seeking for info

    Dead link in documentation / Seeking for info

    Hi! :)

    On the troubleshooting page, the link is dead at this sentence:

    If you use the Symfony CLI and want to use an external hub, be sure to read [this issue](https://github.com/symfony/cli/issues/424).


    On the other hand, I'm trying to configure a Mercure Hub in relation to a Symfony 5.4 installation.

    Here's my Caddyfile.dev:

    # Learn how to configure the Mercure.rocks Hub on https://mercure.rocks/docs/hub/config
    {
    	{$GLOBAL_OPTIONS}
    }
    
    {$SERVER_NAME:localhost}
    
    log {
    	format filter {
    		wrap console
    		fields {
    			uri query {
    				replace authorization REDACTED
    			}
    		}
    	}
    }
    
    {$EXTRA_DIRECTIVES}
    
    route {
    	encode zstd gzip
      
    	mercure {
    		# Transport to use (default to Bolt)
    		transport_url {$MERCURE_TRANSPORT_URL:bolt://mercure.db}
    		# Publisher JWT key
    		publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
    		# Subscriber JWT key
    		subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
    		# Permissive configuration for the development environment
                    cors_origins *
    		publish_origins *
    		demo
    		anonymous
    		subscriptions
    		# Extra directives
    		{$MERCURE_EXTRA_DIRECTIVES}
    	}
    
    	redir / /.well-known/mercure/ui/
    	respond /healthz 200
    	respond "Not Found" 404
    }
    

    I've served a small test route to test the hub with javascript :

    {% block body %}
        <h1>Test Mercure</h1>
        <button id="publish-button">Publish notification</button>
        <div id="notification-container"></div>
    
        <script>
          const sourceUrl = "{{ mercure('http://localhost:9090/.well-known/mercure/events')|escape('js') }}"
          const eventSource = new EventSource(sourceUrl, {withCredentials: false})
          console.log(eventSource);
          eventSource.onmessage = event => {
            // Will be called every time an update is published by the server
            console.log(JSON.parse(event.data))
          }
    
          const publishButton = document.getElementById('publish-button')
          publishButton.addEventListener('click', () => {
            fetch('http://localhost:9090/.well-known/mercure', {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
              },
              body: JSON.stringify(
                {
                    text: 'Test notification'
                }
              )
            })
            .then(response => console.log('Notification published!'))
            .catch(error => console.error('Error during process:', error))
          })
        </script>
    {% endblock %}
    

    Whenever I try to hit the button I get a CORS error: Access to fetch at 'http://localhost:9090/.well-known/mercure' from origin 'https://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

    Am I missing something, maybe that was pointed out on the dead link from the documentation? It seems using anonymous mode + cors_origins * should prevent CORS errors and the need to use JWT validation?

    Thanks in advance for any piece of help and cheers anyway!

  • spec: Rename mercure_subscribers metrics to mercure_subscribers_gauge

    spec: Rename mercure_subscribers metrics to mercure_subscribers_gauge

    This change allow Datadog agent to fetch all metrics starting with mercure_subscribers

    • mercure_subscribers_gauge (previously mercure_subscribers)
    • mercure_subscribers_total

    See https://github.com/dunglas/mercure/issues/720 issue for more information

  • Deploy mercure bundle in test server

    Deploy mercure bundle in test server

    Hi excelent work guys,

    Sorry for my english, i need help in deploy config please, i don't khown if have a bug or error in my config nginx, in my log Developer Tools i see this error:

    EventSource's response has a MIME type ("text/html") that is not "text/event-stream". Aborting the connection.

    I read many issues but I did not find a solution.

    Symfony 5.4.9 Ionic Angular 6.20.3 symfony/mercure-bundle 0.3.5

    My template (nginx docker) server { listen 80 default_server; server_name _; return 301 https://my-domain.es; }

    server { listen 443 ssl default_server; server_name ${NGINX_DOMAIN_TEST}; root /var/www/api-project/public; ssl_protocols TLSv1.3; ssl_prefer_server_ciphers on; ssl_certificate /etc/ssl/certs/my-cert.es.chained.crt; ssl_certificate_key /etc/ssl/private/my-key.es.key;

    location / {
        # try to serve file directly, fallback to index.php
        try_files $uri /index.php$is_args$args;
    }
    
    location /.well-known/mercure {
        proxy_pass http://mercure:3000/.well-known/mercure;
    chunked_transfer_encoding off;
    proxy_buffering off;
    proxy_cache off;
        proxy_read_timeout 24h;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    
        ## Be sure to set USE_FORWARDED_HEADERS=1 to allow the hub to use those headers ##
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    

    }

    My .ts (ionic angular) subscribeEventSource() { const url = new URL('https://my-domain.es/.well-known/mercure');

    url.searchParams.append(
      'topic',
      `https://${host}` + '/api/show/chat/' + this.user.rooms_id
    );
    const es = new EventSource(url, { withCredentials: true });
    
    es.onmessage = (event: any) => {
      let message = JSON.parse(event.data);
      const user = this.user.users_id;
     // Do something ...
    }
    

    }

    My controller #[Route("/show/chat/{id}", name: "chat_show")] public function showChat( Request $request, Room $room, MessageRepository $messageRepository, SerializerInterface $serializer ): Response { $host = $this->toolsService->getHost(); $messages = $messageRepository->findBy( [ "room" => $room, ], ["created_at" => "ASC"] );

    $messages = $serializer->serialize($messages, "json", [
      "groups" => ["message"],
    ]);
    
    $userConnected = $this->user->getId();
    
    $subscribe = "https://" . $host . "/api/show/chat/" . $room->getId();
    $tokenJWT = $this->toolsService->getJWT($subscribe);
    
    $response = new JsonResponse(
      [
        "messages" => $messages,
      ],
      Response::HTTP_OK
    );
    
    $response->headers->setCookie(
      Cookie::create("mercureAuthorization")
        ->withValue($tokenJWT)
        ->withExpires()
        ->withPath("/")
        ->withDomain($host)
        ->withSecure(true)
        ->withHttpOnly(true)
        ->withSameSite(Cookie::SAMESITE_NONE)
    );
    
    $response->headers->set("Content-Type", "text/event-stream");
    $response->headers->set("Cache-Control", "no-cache");
    
    return $response;
    

    }

    Run in device android - log DevTools : log

    Config docker-compose mercure: docker-compose

    Config docker-compose-override mercure: docker-override

    Questions: Is there something you need to do to implement mercure-container on a server? Why no documentation of deploy in prod only localhost?

    Thanks :)

  • Datadog and Mercure metrics

    Datadog and Mercure metrics

    Context

    Mercure Hub: v0.14.2

    Problem

    Hi, I recently needed to use Mercure metrics given by the /metrics Caddy endpoint in a Datadog dashboard.

    Unfortunately, I was not able to use correctly the value from the mercure_subscribers metric.

    Datadog only get the gauge and not the counter (_total).

    The result was not the expected one (see capture below).

    image

    As you can see, the value continue to increase indefinitely.

    With the mercure_updates, I was able to use the counter (no gauge are given) so the result was the expected.

    image

    Test case

    I deployed an instance of Mercure in Rancher with the following settings:

    version: '3'
    
    services:
      mercure-hub:
        image: dunglas/mercure:v0.14.2
        labels:
          com.datadoghq.ad.check_names: '["openmetrics"]'
          com.datadoghq.ad.init_configs: '[{}]'
          com.datadoghq.ad.instances: |
            [
              {
                "openmetrics_endpoint": "http://%%host%%/metrics",
                "metrics": [
                  "mercure_subscribers",
                  "mercure_updates",
                  "caddy_http_requests"
                ]
              }
            ]
        environment:
          MERCURE_PUBLISHER_JWT_KEY: "${MERCURE_HUB_JWT_KEY}"
          MERCURE_SUBSCRIBER_JWT_KEY: "${MERCURE_HUB_JWT_KEY}"
          MERCURE_TRANSPORT_URL: bolt:///data/updates.db
          MERCURE_EXTRA_DIRECTIVES: |
            anonymous true
            cors_origins ${CORS_ALLOWED_ORIGINS}
            heartbeat 20s
          GLOBAL_OPTIONS: |
            admin off
          EXTRA_DIRECTIVES: |
            handle /metrics {
              metrics
            }
          SERVER_NAME: ':80' # Disable native HTTPS of Caddy server
    

    I created a new widget in my dashboard and search for the mercure_subscribers metric as counter:

    image

    As you can see, only the gauge are present.

    I tried locally with a Prometheus + Grafana and I was able to query both metrics: mercure_subscribers as a gauge and as a counter

    Expected behavior

    Datadog is able to get gauge and counter metric types when both exists.

    Proposition

    Try to do something like Caddy:

    # HELP caddy_http_requests_in_flight Number of requests currently handled by this server.
    # TYPE caddy_http_requests_in_flight gauge
    caddy_http_requests_in_flight{handler="metrics",server="srv0"} 1
    caddy_http_requests_in_flight{handler="subroute",server="srv0"} 1
    
    # HELP caddy_http_requests_total Counter of HTTP(S) requests made.
    # TYPE caddy_http_requests_total counter
    caddy_http_requests_total{handler="metrics",server="srv0"} 5
    caddy_http_requests_total{handler="subroute",server="srv0"} 5
    
  • Failed to send an update.

    Failed to send an update.

    Hello, i am just starting with mercure and i launched my first mercure server and got some errors.

    I have build an API and wan't to have real time notifications on my reactjs front end app.

    Here is the mercure server launched

    server started

    Then i created a JWT:

    jwt created

    My symfony .env file looks like:

    env

    So i first used postman to make a post request to http://localhost:3000/.well-known/mercure, and that worked perfectly, my front end application was updated successfully.

    Now i want to Use the mercure attribute to hint API Platform that it must dispatch updates so that any time an object of my entity type is created, updated or deleted, the new version is sent to all connected clients through the Mercure hub

    My entity looks like below:

    #[ORM\Entity(repositoryClass: ConversationRepository::class)] #[ApiResource( mercure:true , security:'is_granted("ROLE_USER")' , operations:[ new Delete( openapiContext:[ 'security' => [[ 'bearerAuth' => [] ]] , ] ) , new Get( uriTemplat

    You can see that mercure is set to trrue, but when there is a post, put or delete request on my entity, i get the following errors error

    The mercure console gives me the following error

    {"level":"info","ts":1668685032.1344423,"caller":"mercure/publish.go:21","msg":"Topic selectors not matched, not provided or authorization error","remote_addr":"127.0.0.1:38880","error":"unable to parse JWT: signature is invalid"} 127.0.0.1 - - [17/Nov/2022:12:37:12 +0100] "POST /.well-known/mercure HTTP/1.1" 401 13 "" "Symfony HttpClient/Curl"

    I really don't know what i did wrong, meanwhile it works normally when i use post man to perform a post request to mercure hub.

    I am stocked at this point for a while, i haven't seen something helpful on the internet yet

Implementation of the NELI leader election protocol for Go and Kafka
Implementation of the NELI leader election protocol for Go and Kafka

goNELI Implementation of the NELI leader election protocol for Go and Kafka. goNELI encapsulates the 'fast' variation of the protocol, running in excl

Dec 8, 2022
⚡ HTTP/2 Apple Push Notification Service (APNs) push provider for Go — Send push notifications to iOS, tvOS, Safari and OSX apps, using the APNs HTTP/2 protocol.

APNS/2 APNS/2 is a go package designed for simple, flexible and fast Apple Push Notifications on iOS, OSX and Safari using the new HTTP/2 Push provide

Jan 1, 2023
RES Service protocol library for Go

RES Service for Go Synchronize Your Clients Go package used to create REST, real time, and RPC APIs, where all your reactive web clients are synchroni

Nov 23, 2022
⚡️ A lightweight service that will build and store your go projects binaries, Integrated with Github, Gitlab, Bitbucket and Bitbucket Server.
⚡️ A lightweight service that will build and store your go projects binaries, Integrated with Github, Gitlab, Bitbucket and  Bitbucket Server.

Rabbit A lightweight service that will build and store your go projects binaries. Rabbit is a lightweight service that will build and store your go pr

Nov 19, 2022
Embedded, Fast and Persistent bigqueue implementation

bigqueue bigqueue provides embedded, fast and persistent queue written in pure Go using memory mapped (mmap) files. bigqueue is now thread safe as wel

Sep 24, 2022
ChizBroker is a fast and simple GRPC based implementation of kafka.
ChizBroker is a fast and simple GRPC based implementation of kafka.

Chiz Broker: a broker for fun ChizBroker is a fast and simple GRPC based implementation of kafka. Features: Ready to be deployed on kubernetes Prometh

Oct 30, 2022
Uniqush is a free and open source software system which provides a unified push service for server side notification to apps on mobile devices.

Homepage Download Blog/News @uniqush Introduction Uniqush (\ˈyü-nə-ku̇sh\ "uni" pronounced as in "unified", and "qush" pronounced as in "cushion") is

Jan 9, 2023
graylog-golang is a full implementation for sending messages in GELF (Graylog Extended Log Format) from Go (Golang) to Graylog

graylog-golang is a full implementation for sending messages in GELF (Graylog Extended Log Format) from Go (Golang) to Graylog

Dec 5, 2022
🔊Minimalist message bus implementation for internal communication

?? Bus Bus is a minimalist event/message bus implementation for internal communication. It is heavily inspired from my event_bus package for Elixir la

Jan 3, 2023
The implementation of the pattern observer

Event This is package implements pattern-observer Fast example import ( "github.com/agoalofalife/event" ) func main() { // create struct e := even

Dec 4, 2022
Package notify provides an implementation of the Gnome DBus Notifications Specification.

go-notify Package notify provides an implementation of the Gnome DBus Notifications Specification. Examples Display a simple notification. ntf := noti

Dec 27, 2022
mangos is a pure Golang implementation of nanomsg's "Scalablilty Protocols"
mangos is a pure Golang implementation of nanomsg's

mangos Mangos™ is an implementation in pure Go of the SP (“Scalability Protocols”) messaging system. These are colloquially known as a “nanomsg”. ❗ Th

Jan 1, 2023
POC of an event-driven Go implementation

Event Driven example in Golang This POC shows an example of event-driven architecture with a working domain event broker, an event producer and a cons

Nov 2, 2021
Scalable real-time messaging server in language-agnostic way
Scalable real-time messaging server in language-agnostic way

Centrifugo is a scalable real-time messaging server in language-agnostic way. Centrifugo works in conjunction with application backend written in any

Jan 2, 2023
golang long polling library. Makes web pub-sub easy via HTTP long-poll server :smiley: :coffee: :computer:
golang long polling library.  Makes web pub-sub easy via HTTP long-poll server :smiley: :coffee: :computer:

golongpoll Golang long polling library. Makes web pub-sub easy via an HTTP long-poll server. New in v1.1 Deprecated CreateManager and CreateCustomMana

Jan 6, 2023
Golang push server cluster
Golang push server cluster

gopush-cluster gopush-cluster is a go push server cluster. Features light weight high performance pure golang implementation message expired offline m

Dec 28, 2022
A push notification server written in Go (Golang).
A push notification server written in Go (Golang).

gorush A push notification micro server using Gin framework written in Go (Golang) and see the demo app. Contents gorush Contents Support Platform Fea

Jan 8, 2023
websocket based messaging server written in golang

Guble Messaging Server Guble is a simple user-facing messaging and data replication server written in Go. Overview Guble is in an early state (release

Oct 19, 2022
High-Performance server for NATS, the cloud native messaging system.
High-Performance server for NATS, the cloud native messaging system.

NATS is a simple, secure and performant communications system for digital systems, services and devices. NATS is part of the Cloud Native Computing Fo

Jan 2, 2023