This repository has been archived on 2025-01-19. You can view files and clone it, but cannot push or open issues or pull requests.
oliverdavies.uk-old-sculpin/source/_posts/2019-09-13-live-blogging-symfonylive-london.md

10 KiB
Raw Blame History

title tags
Live Blogging From SymfonyLive London 2019
conference
symfony
symfonylive
php

Inspired by Matt Stauffer's live blogging of the keynote at Laracon US, Im going to do the same for the sessions that Im attending at SymfonyLive London 2019...

Keynote (Back to the basics)

Embrace the Linux philosophy

  • How we grow the Symfony ecosystem. Built abstracts.
  • HttpFoundation, HttpKernel
  • Moved to infrastructure
  • A few abstractions on top of PHP. Improved versions of PHP functions (dump and var_dump)
  • Started a add higher level abstractions (e.g. Mailer), built on the lower ones.
  • Recently worked on PHPUnit assertions. Mailer in Symony 4.4. Can test if an email is sent or queued

Building flexible high-level abstractions on top of low-level ones

What's next?

  • Mailer announced in London last year. New component.
  • System emails? e.g. new customer, new invoice.
  • Symfony Mailer = Built-in responsive, flexible, and generic system emails
    • Twig with TwigExtraBundle
    • Twig inky-extra package (Twig 1.12+)
    • Zurb Foundation for Emails CSS stylesheet
    • Twig cssinliner-extra package (Twig 1.12+)
    • Optimised Twig layouts
  • SystemEmail class extends templated email
  • Can set importance,
  • Customisable
  • Always trying to keep flexible, so things can be overidden and customised

Sending SMS messages

  • new Texter and SmsMessage class for sending SMS messages
  • Same abstraction as emails, but for SMS messages
  • Based on HttpClient + Symfony Messenger and third-party providers (Twilio and Nexmo) twilio:// and nemxo://
  • Can set via transport $sms->setTransport('nexmo')
  • Extend the SystemEmail and do what you want
  • Failover

Sending Messages

  • Create ChatMessage
  • Telegram and Slack
  • $message->setTransport('telegram'), $bus->dispatch($message)
  • Send to Slack and Telegram
  • SlackOptions and TelegramOptions for adding emojis etc
  • Common transport layer TransportInterface, MessageInterface
  • Failover - e.g. if Twilio is down, send to Telegram

New component - SymfonyNotifier

  • Channels - email, SMS, chat
  • Transport, slack, telegram, twilio
  • Create a notification, arguments are message and transports (array)
  • Receiver
  • Customise notifications, InvoiceNotification extends Notification. getChannels
    • Override default rendering
    • ChatNotificationInterface - asChatMessage()
  • Semantic configuration
    • composer req twilio-notifier telegram-notifier
  • Channels
    • Mailer
    • Chatter
    • Texter
    • Browser
    • Pusher (iOS, Android, Desktop native notifications)
    • Database (web notification centre)
    • A unified way to notify Users via a unified Transport layer
  • Each integration is only 40 lines of code

What about a SystemNotification?

  • Autoconfigured channels
  • new SystemNotification, Notifier::getSystemReceivers
  • Importance, automatically configures channels
  • Different channels based on importance
  • ExceptionNotification - get email with stack trace attached

Notifier

  • send messages via a unified api
  • send to one or many receivers
  • Default configu or custom one

### How can we leverage this new infrastructure?

  • Monolog NotifierHandler - triggered on Error level logs

  • Uses notified channel configuration

  • Converts Error level logs to importance levels

  • Configurablelike other Notifications

  • 40 lines of code

  • Failed Messages Listener - 10 lines of glue code

  • Experimental component in 5.0

  • Can't in in 4.4 as it's a LTS version

  • First time an experimental component is added

  • Stable in 5.1

Queues, busses and the Messenger component (Tobias Nyholm)

  • Stack is top and buttom - Last-in, first-out
  • Queue is back and front - last in, first out

2013

  • Using Symfony, used 40 or 50 bundles in a project - too much information!
  • Used to copy and paste, duplicate a lot of code
  • Testing your controllers - controllers as services?
  • Controllers are 'comfortable'
  • Tried adding CurrentUserProvider service to core, should be passed as an argument. Cannot test.
  • 'Having Symfony all over the place wasn't the best thing' - when to framework (Matthias Noback)
    • Hexagonal architecture
    • Keep your kernel away from infrastructure. Let the framework handle the infrastructure.
  • Controller -> Command -> Command Bus -> CommandHandler

What did we win?

  • Can leverage Middleware with a command bus
  • Queues as a service (RabbitMQ)
  • Work queue - one producer, multiple consumers
  • Queues should be durable - messages are also stored on disk, consumers should acknowledge a message once a message is handled
  • Publish/subscribe
    • Producer -> Fanout/direct with routing (multiple queues) -> multiple consumers
  • Topics - wildcards

2016

  • New intern. Understand everything, 'just PHP'. Plain PHP application, not 'scary Symfony'

Symfony Messenger

  • composer req symfony/messager - best MessageBus implementation
  • Message -> Message bus -> Message handler
  • Message is a plain PHP class
  • Handler is a normal PHP class which is invokable
  • messenger:message_hander tag in config
  • Autowire with MessageHandlerInterface
  • What if it takes 20 seconds to send a message? Use asynchronous.
  • Transports as middleware (needs sender, receiver, configurable with DSN, encode/decode). MESSENGER_DSN added to .env
  • Start consumer with bin/console messager:consume-messages. Time limit with --time-limit 300
  • PHP Enqueue - production ready, battle-tested messaging solution for PHP

Issues

  • Transformers, takes an object and transforms into an array - FooTransformer implements TransformerInterface.
  • Don't break other apps by changing the payload.

Multiple buses

  • Command bus, query bus, event bus
  • Separate actions from reactions

Envelope

  • Stamps for metadata - has the item been on the queue already?

Failures

  • Requeue, different queue or same queue after a period of time
  • Failed queue 1 every minute, failed queue 2 every hour - temporary glitches or a bug?

Creating entities

  • What if two users registered at the same tiem? Use uuids rather than IDs.

  • Symfony validation - can be used on messages, not just forms.

  • Cache everything

    • Option 1: HTTP request -> Thin app (gets responses from Redis) -> POST to queue. Every GET request would warm cache
    • Option 2: HTTP request -> Thin app -> return 200 response -> pass to workers
  • Tip: put Command and CommandHandlers in the same directory

## HttpClient (Nicolas Grekas)

  • new symfony component, released in may
  • Httpclient contracts, separate package that contains interfaces
    • Symfony
    • PHP-FIG
    • Httplug
  • HttpClient::create(). $client->get()
  • JSON decoded with error handling
  • Used on symfony.com website (#1391). Replaces Guzzle Client for HttpClientInterface
  • Object is stateless, Guzzle is not. Doesn't handle cookies, cookies are state
  • Remove boilerplate - use toArray()
  • Options as third argument - array of headers, similar to Guzzle

What can we do with the Response?

  • getStatusCode(): int
  • getHeaders(): array
  • getContent(): string
  • toArray(): array
  • cancel(): void
  • getInfo(): array - metadata
  • Everything is lazy!
  • 80% of use-cases covered

What about PSR-18?

  • Decorator/adapter to change to PSR compatible
  • Same for Httplug

What about the remaining 20%?

  • Options are part of the abstraction, not the implementation

Some of the options

  • timeout - control inactivity periods

  • proxy - get through a http proxy

  • on_progress - display a progress bar / build a scoped client

  • base_url - resolve relative URLS / build a scoped client

  • resolve - protect webhooks against calls to internal endpoints

  • max_redirects - disable or limit redirects

  • Robust and failsafe by default

  • Streamable uploads - $mimeParts->toIterable().

  • donwload a file

    foreach ($client->stream($response) as $chunk) {
        // ... 
    }
    
  • Responses are lazy, requests are concurrent
  • Asychronus requests. Reading in network order
foreach ($client->stream($responses) as $response => $chunk) {
    if ($chunk->isLast()) {
        // a $response completed
    } else {
        // a $response's got network activity or timeout
    }
}
  • 379 request completed in 0.4s!
  • Stream has second argument, max number of seconds to wait before yielding a timeout chunk
  • ResponseInterface::getInfo() - get response headers, redirect count and URL, start time, HTTP method and code, user data and URL
    • getInfo('debug') - displays debug information

The components

  • NativeHttpClient and CurlHttpClient
    • both provide
      • 100% contracts
      • secure directs
      • extended (time) info
      • transparent HTTP compression and (de)chunking
      • automatic HTTP proxy configuration via env vars

NativeHttpClient

  • is most portable, works for everyone
  • based on HTTP stream wrapper with fixed redirect logic
  • blocking until response headers arrive

CurlHttpClient

  • Requires ext-curl with fixed redirection logic
  • Multiplexing response headers and bodies
  • Leverages HTTP/2 and PUSH when available
  • Keeps connections open also between synchronous requests, no DNS resolution so things are faster

Decorators

  • ScopingHttpClient - auto-configure options based on request URL
  • MockHttpClient - for testing, doesn't make actual HTTP requests
  • CachingHttpClient - adds caching on a HTTP request
  • Psr18Client
  • HttplugClient
  • TraceableHttpClient

Combining

FrameworkBundle/Autowiring

framework:
    http_client:
        max_host_connections: 4
        deault_options:
            # ....
    scoped_client:
        # ...

HttpBrowser

  • HttpClient + DomCrawler + CssSelector + HttpKernel + BrowserKit
  • RIP Goutte!

Coming in 4.4...

  • max_duration
  • buffer based on a callable
  • $chunk->isInformational()
  • $response->toStream()
  • Async-compatible extensibility, when decoration is not enough

composer req symfony/http-client

Symfony Checker is coming (Valentine Boineau)