Skip to content

Commit

Permalink
Merge pull request #1045 from eleven-labs/fix/broken-links
Browse files Browse the repository at this point in the history
fix: SEO: fix broken links
  • Loading branch information
ch3ric authored Dec 15, 2023
2 parents e8a3b11 + c2e6188 commit e029c64
Show file tree
Hide file tree
Showing 90 changed files with 237 additions and 237 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ And to specify a size on the image, you can add the arguments (`width`, `height`
![alt of image]({BASE_URL}/imgs/articles/YYYY-MM-DD-slug/image-name.png?width=500)
```

If you need to add internal anchor links from your article to other article of our blog, use this syntax:
```md
[title of destination article]({BASE_URL}/fr/destination-article-slug)
```

> Warning: Don't add html in your markdown, you don't have to override the blog template in the markdown.
**4 - Add your pull request**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,6 @@ Test
```

Varnish will recognize the use of an ESI and will therefore cache two objects, one for the full page with the cache data of the page and one for ESI with other cache data. You can then uncache the ESI only and Varnish will update a single object (only one request to the server); the user has all the pages updated just the same.
For further information, I suggest you look at a previous [article](https://blog.eleven-labs.com/symfony-2-cache-http-esi/), which explains an implementation for Symfony.
For further information, I suggest you look at a previous [article]({BASE_URL}/symfony-2-cache-http-esi/), which explains an implementation for Symfony.
You can also find a presentation about HTTP caches and Symfony [ici](https://docs.google.com/presentation/d/1RVr_JfpFKVRXdg4hy6war3OfiSJtdeYzFsdxhn2t0NY/edit?usp=sharing).
.
6 changes: 3 additions & 3 deletions _articles/en/2016-11-17-php_handle-exception-gracefully.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,10 @@ On the other hand, the exception should not be placed under the mat, but it shou

An exception well launched and managed correctly allows your application to be easily maintainable and makes the diagnosis of an error simpler and faster.

### Other post on same subject
* [PHP 7 Throwable Errors Exceptions](/en/fr/php7-throwable-error-exception/)
### Other post on same subject
* [PHP 7 Throwable Errors Exceptions]({BASE_URL}/en/php7-throwable-error-exception/)

### References
### References

- http://wiki.c2.com/?ExceptionPatterns
- http://www.phptherightway.com/\#exceptions
Expand Down
2 changes: 1 addition & 1 deletion _articles/en/2016-11-21-push-notification-website.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ keywords:
- notification
---

In a [previous article](https://blog.eleven-labs.com/fr/votre-premiere-pwa/) we created our first PWA, but we haven't seen the whole concept. The convenience of [PWA](https://blog.eleven-labs.com/fr/progressive-web-apps-au-googledevsummit/) is to act like a mobile application, to be installed on a phone, to manage off-line mode, and especially to send push notifications. Notifications are the essential element of user involvement, they allow to send a reminder and to communicate with our users. We are going to finalize the last tutorial by setting up a simple push notification system, using [Firebase](https://firebase.google.com/) to store user tokens.
In a [previous article]({BASE_URL}/fr/votre-premiere-pwa/) we created our first PWA, but we haven't seen the whole concept. The convenience of [PWA]({BASE_URL}/fr/progressive-web-apps-au-googledevsummit/) is to act like a mobile application, to be installed on a phone, to manage off-line mode, and especially to send push notifications. Notifications are the essential element of user involvement, they allow to send a reminder and to communicate with our users. We are going to finalize the last tutorial by setting up a simple push notification system, using [Firebase](https://firebase.google.com/) to store user tokens.

To go quicker, we invite you to catch up by retrieving the project [https://github.com/CaptainJojo/pwa-parisjs](https://github.com/CaptainJojo/pwa-parisjs) that contains a ready to go PWA.

Expand Down
58 changes: 28 additions & 30 deletions _articles/en/2017-01-31-rabbitmq-publish-consume-retry-messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ keywords:
---
![Swarrot Logo]({BASE_URL}/imgs/articles/2017-01-23-publier-consommer-reessayer-des-messages-rabbitmq/logo.png)

RabbitMQ is a message broker, allowing to process things asynchronously. There's already an [article](https://blog.eleven-labs.com/fr/creer-rpc-rabbitmq/) written about it, if you're not familiar with RabbitMQ.
RabbitMQ is a message broker, allowing to process things asynchronously. There's already an [article]({BASE_URL}/fr/creer-rpc-rabbitmq/) written about it, if you're not familiar with RabbitMQ.

What I'd like to talk to you about is the lifecycle of a message, with error handling. Everything in a few lines of code.

Expand All @@ -28,17 +28,17 @@ Therefore, we're going to configure a RabbitMQ virtual host, publish a message,

The technical solution is based on two libraries:

* [RabbitMQ Admin Toolkit](https://github.com/odolbeau/rabbit-mq-admin-toolkit) : PHP library the interacts with the HTTP API of our RabbitMQ server, to create exchanges, queues...
* [Swarrot](https://github.com/swarrot/swarrot) : PHP library to consume and publish our messages.
* [RabbitMQ Admin Toolkit](https://github.com/odolbeau/rabbit-mq-admin-toolkit) : PHP library the interacts with the HTTP API of our RabbitMQ server, to create exchanges, queues...
* [Swarrot](https://github.com/swarrot/swarrot) : PHP library to consume and publish our messages.

Swarrot is compatible with the amqp extension of PHP, as well as the [php-amqplib](https://github.com/php-amqplib/php-amqplib) library. The PHP extension has a certain advantage on performance (written in C) over the library, based on [benchmarks](https://odolbeau.fr/blog/benchmark-php-amqp-lib-amqp-extension-swarrot.html). To install the extension, click [here](https://serverpilot.io/community/articles/how-to-install-the-php-amqp-extension.html).
The main adversary to Swarrot, [RabbitMqBundle](https://github.com/php-amqplib/RabbitMqBundle), is not compatible with the PHP extension, and is not as simple in both configuration and usage.
Swarrot is compatible with the amqp extension of PHP, as well as the [php-amqplib](https://github.com/php-amqplib/php-amqplib) library. The PHP extension has a certain advantage on performance (written in C) over the library, based on [benchmarks](https://odolbeau.fr/blog/benchmark-php-amqp-lib-amqp-extension-swarrot.html). To install the extension, click [here](https://serverpilot.io/community/articles/how-to-install-the-php-amqp-extension.html).
The main adversary to Swarrot, [RabbitMqBundle](https://github.com/php-amqplib/RabbitMqBundle), is not compatible with the PHP extension, and is not as simple in both configuration and usage.

## Configuration

Our first step will be to create our RabbitMQ configuration: our exchange and our queue.

The RabbitMQ Admin Toolkit library, developed by _[odolbeau](https://github.com/odolbeau),_ allows us to configure our vhost very easily. Here is a basic configuration declaring an exchange and a queue, allowing us to send our mascot Wilson and his fellow friends to space:
The RabbitMQ Admin Toolkit library, developed by _[odolbeau](https://github.com/odolbeau),_ allows us to configure our vhost very easily. Here is a basic configuration declaring an exchange and a queue, allowing us to send our mascot Wilson and his fellow friends to space:

```yaml
# default_vhost.yml
Expand All @@ -60,7 +60,7 @@ The RabbitMQ Admin Toolkit library, developed by _[odolbeau](https://github.co
routing_key: send_astronaut_to_space
```
Here, we ask the creation of an exchange named "default", and a queue named "send_astronaut_to_space", bound to our exchange via a homonym routing key.
Here, we ask the creation of an exchange named "default", and a queue named "send_astronaut_to_space", bound to our exchange via a homonym routing key.
A binding represents a relation between a queue and an exchange.
Let's launch the command to create our vhost:
Expand All @@ -79,11 +79,11 @@ If you connect to the RabbitMQ management interface (ex: http://127.0.0.1:15672/
![Capture of exchanges created]({BASE_URL}/imgs/articles/2017-01-23-publier-consommer-reessayer-des-messages-rabbitmq/create_exchanges.png)
Click on the _Exchanges_ tab: an exchange named _default_ has been created, with a binding to our queue as indicated in our terminal.
Click on the _Exchanges_ tab: an exchange named _default_ has been created, with a binding to our queue as indicated in our terminal.
![Capture of queues created]({BASE_URL}/imgs/articles/2017-01-23-publier-consommer-reessayer-des-messages-rabbitmq/create_queues.png)
Now click on the _Queues_ tab: _send_astronaut_to_space_ is also here.
Now click on the _Queues_ tab: _send_astronaut_to_space_ is also here.
Let's take a look at the publication and consumption of messages.
Expand All @@ -98,7 +98,7 @@ After installing the bundle, we have to configure it:
```yaml
# app/config/config.yml
swarrot:
provider: pecl # pecl or amqp_lib
provider: pecl # pecl or amqp_lib
connections:
rabbitmq:
host: '%rabbitmq_host%'
Expand All @@ -121,11 +121,9 @@ This is a configuration example. The interesting part comes around the "consumer
Every message published in an exchange will be routed to a queue according to its routing jey. Therefore, we need to process a message stored in a queue. Using Swarrot, special things called _processors_ are in charge of this.
To consume a message, we need to create our own processor. As indicated in the documentation, a processor is just a Symfony service who needs to implement the _ProcessInterface_ interface.
To consume a message, we need to create our own processor. As indicated in the documentation, a processor is just a Symfony service who needs to implement the _ProcessInterface_ interface.
![Swarrot - Middleware stack](https://camo.githubusercontent.com/8ac89cd415aebfb1026b2278093dbcc986b126da/68747470733a2f2f646f63732e676f6f676c652e636f6d2f64726177696e67732f642f3145615f514a486f2d3970375957386c5f62793753344e494430652d41477058527a7a6974416c59593543632f7075623f773d39363026683d373230)
The particularity of processors is that they work using middlewares, allowing to add behavior before and/or after the processing of our message (our processor). That's why there is a _middleware_stack_ parameter, that holds two things: _swarrot.processor.exception_catcher_ and _swarrot.processor.ack_. Although optional, these middlewares bring nice flexibility. We'll come back on this later on.
The particularity of processors is that they work using middlewares, allowing to add behavior before and/or after the processing of our message (our processor). That's why there is a _middleware_stack_ parameter, that holds two things: _swarrot.processor.exception_catcher_ and _swarrot.processor.ack_. Although optional, these middlewares bring nice flexibility. We'll come back on this later on.
```php
<?php
Expand Down Expand Up @@ -155,7 +153,7 @@ Once again, it's very simple to publish messages with Swarrot. We only need to d
```yaml
# app/config/config.yml
consumers:
# ...
# ...
middleware_stack:
- configurator: swarrot.processor.exception_catcher
- configurator: swarrot.processor.ack
Expand All @@ -167,7 +165,7 @@ Once again, it's very simple to publish messages with Swarrot. We only need to d
routing_key: send_astronaut_to_space
```
The secret is to declare a new message type, specifying the _connection_, _exchange_, and the _routing key._ Then publish a message this way:
The secret is to declare a new message type, specifying the _connection_, _exchange_, and the _routing key._ Then publish a message this way:
```php
<?php
Expand All @@ -176,9 +174,9 @@ $message = new Message('Wilson wants to go to space');
$this->get('swarrot.publisher')->publish('send_astronaut_to_space_publisher', $message);
```

The service _swarrot.publisher_ deals with publishing our message. Simple right?
The service _swarrot.publisher_ deals with publishing our message. Simple right?

After setting up _queues_, published and consumed a message, we now have a good view of the life-cycle of a message.
After setting up _queues_, published and consumed a message, we now have a good view of the life-cycle of a message.

## Handling errors

Expand All @@ -187,11 +185,11 @@ One last aspect I'd like to share with you today is about errors while consuming
Setting aside implementation problems in your code, it's possible that you encounter exceptions, due to external causes. For instance, you have a processor that makes HTTP calls to an outside service. The said service can be temporarily down, or returning an error. You need to publish a message and make sure that this one is not lost. Wouldn't it be great to publish this message again if the service does not respond? And do so after a certain amount of time?

Somewhere along the way, I've been confronted to this problem. We knew such things could happen and we needed to automatically "retry" our messages publication.
I'm going to show you how to proceed, keeping our example _send_astronaut_to_space._ Let's decide that we're going to retry the publication of our message 3 times maximum. To do that, we need 3 retry queues. Fortunately, configuration of retry queues and exchanges is so easy with [RabbitMQ Admin Toolkit](https://github.com/odolbeau/rabbit-mq-admin-toolkit): we only need one line! Let's see this more closely :
I'm going to show you how to proceed, keeping our example _send_astronaut_to_space._ Let's decide that we're going to retry the publication of our message 3 times maximum. To do that, we need 3 retry queues. Fortunately, configuration of retry queues and exchanges is so easy with [RabbitMQ Admin Toolkit](https://github.com/odolbeau/rabbit-mq-admin-toolkit): we only need one line! Let's see this more closely :

```yaml
# default_vhost.yml
# ...
# ...
queues:
send_astronaut_to_space:
durable: true
Expand Down Expand Up @@ -226,8 +224,8 @@ Create binding between exchange default and queue send_astronaut_to_space (with
We still create a default exchange. Then, many things are done:
* Creation of an exchange called _dl_ and queues _queues_ _send_astronaut_to_space and_ _send_astronaut_to_space_dl_ : we'll come back on this later on.
* Creation of an exchange called _retry_ and queues _send_astronaut_to_space_retry_1_, _send_astronaut_to_space_retry_2_ and _send_astronaut_to_space_retry_3_: here is the interesting part, all queues that will be used to do a retry of our message.
* Creation of an exchange called _dl_ and queues _queues_ _send_astronaut_to_space and_ _send_astronaut_to_space_dl_ : we'll come back on this later on.
* Creation of an exchange called _retry_ and queues _send_astronaut_to_space_retry_1_, _send_astronaut_to_space_retry_2_ and _send_astronaut_to_space_retry_3_: here is the interesting part, all queues that will be used to do a retry of our message.
Now let's configure our consumer.
Expand All @@ -236,7 +234,7 @@ With Swarrot, handling of retries is very easy to configure. Do you remember tho
```yaml
# app/config/config.yml
consumers:
# ...
# ...
middleware_stack:
- configurator: swarrot.processor.exception_catcher
- configurator: swarrot.processor.ack
Expand All @@ -253,13 +251,13 @@ With Swarrot, handling of retries is very easy to configure. Do you remember tho
routing_key: send_astronaut_to_space
```
The main difference with our previous configuration is located around the parameter _middleware_stack_: we need to add the processor _swarrot.processor.retry_, with its retry strategy:
The main difference with our previous configuration is located around the parameter _middleware_stack_: we need to add the processor _swarrot.processor.retry_, with its retry strategy:
* the name of the retry exchange (defined above)
* the number of publishing attempts
* the pattern of retry queues
The workflow works this way: if the message is not _acknowledged_ followingan exception the first time, it will be published in the _retry_ exchange_,_ with routing key_send_astronaut_to_space_retry_1\._ Then, 5 seconds later, the message is published back in our main queue _send_astronaut_to_space_. If another error is encountered, it will be republished in the retry exchange, with the routing key _send_astronaut_to_space_retry_2_, and 25 seconds later the message will be back on our main queue. Same thing one last time with 100 seconds.
The workflow works this way: if the message is not _acknowledged_ followingan exception the first time, it will be published in the _retry_ exchange_,_ with routing key_send_astronaut_to_space_retry_1\._ Then, 5 seconds later, the message is published back in our main queue _send_astronaut_to_space_. If another error is encountered, it will be republished in the retry exchange, with the routing key _send_astronaut_to_space_retry_2_, and 25 seconds later the message will be back on our main queue. Same thing one last time with 100 seconds.
```bash
bin/console swarrot:consume:send_astronaut_to_space send_astronaut_to_space
Expand All @@ -271,10 +269,10 @@ bin/console swarrot:consume:send_astronaut_to_space send_astronaut_to_space
[2017-01-12 12:55:51] app.ERROR: [ExceptionCatcher] An exception occurred. This exception has been caught. {"swarrot_processor":"exception","exception":"[object] (Exception(code: 0): An error occurred while consuming hello at /home/gus/dev/swarrot/src/AppBundle/Processor/SendAstronautToSpace.php:12)"}
```
When creating our virtual host, we saw that an exchange called _dl ,_ associated to a queue _send_astronaut_to_space_dl_ has been created. This queue is our message's last stop if the retry mechanism is not able to successfully publish our message (an error is still encountered after each retry).
If we look closely the details of queue _send_astronaut_to_space_, we see that "_x-dead-letter-exchange_" is equal to"_dl_", and that "_x-dead-letter-routing-key_" is equal to "_send_astronaut_to_space_", corresponding to our binding explained previously.
When creating our virtual host, we saw that an exchange called _dl ,_ associated to a queue _send_astronaut_to_space_dl_ has been created. This queue is our message's last stop if the retry mechanism is not able to successfully publish our message (an error is still encountered after each retry).
If we look closely the details of queue _send_astronaut_to_space_, we see that "_x-dead-letter-exchange_" is equal to"_dl_", and that "_x-dead-letter-routing-key_" is equal to "_send_astronaut_to_space_", corresponding to our binding explained previously.
On every error in our processor, the _retryProcessor_ will catch this error, and republish our message in the retry queue as many times as we've configured it. Then Swarrot will hand everything to RabbitMQ to route our message to the queue queue _send_astronaut_to_space_dl._
On every error in our processor, the _retryProcessor_ will catch this error, and republish our message in the retry queue as many times as we've configured it. Then Swarrot will hand everything to RabbitMQ to route our message to the queue queue _send_astronaut_to_space_dl._
## Conclusion
Expand All @@ -283,5 +281,5 @@ Tied to RabbitMQ Admin Toolkit to configure exchanges and queues, Swarrot will a
## References
* [RabbitMQ Admin Toolkit](https://github.com/odolbeau/rabbit-mq-admin-toolkit)
* [Swarrot](https://github.com/swarrot/swarrot)
* [RabbitMQ Admin Toolkit](https://github.com/odolbeau/rabbit-mq-admin-toolkit)
* [Swarrot](https://github.com/swarrot/swarrot)
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ keywords:
- spelling
---

Our blog is built with Jekyll and Github Pages: [more details there (in French)](/fr/migration-du-blog/). So to publish any blog post, each author has to open a new pull request on Github to submit his new markdown files.
Our blog is built with Jekyll and Github Pages: [more details there (in French)]({BASE_URL}/fr/migration-du-blog/). So to publish any blog post, each author has to open a new pull request on Github to submit his new markdown files.
Then the other astronauts can review what was written before merging, i.e. publishing the post. Of course the goal of this review is to make sure everything is explained properly and not to find all the typos, otherwise reviewing would be boring! ;)

That's why we needed to find a way to easily find the misspelled words in the files changed in each pull request, to ease the reviewing process. Of course we knew that none of the automated spell checkers were perfect, we just wanted this tool to send notifications about the mistakes on the pull requests without blocking the developers to merge.
Expand Down
Loading

0 comments on commit e029c64

Please sign in to comment.