Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

A SOA approximation on symfony

346 views

Published on

A little presentation about how we squeezed Symfony to implement some sort of SOA

better see here
https://docs.google.com/presentation/d/1TnDjbERj8F6UgqbZ7fJQsAL6yfg5G56G1iTqSzeTUE8/pub?start=false&loop=false&delayms=3000

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

A SOA approximation on symfony

  1. 1. A SOA Approximation using Symfony Joseluis Laso & Carlos Agudo
  2. 2. Who we are •Carlos Agudo (@karloslupus) •Joseluis Laso (@jl_laso) And Others.. (Spanish team) • Petar Georgiev (@pgkirilov) • Daniel Abad (@ruudy_es) • Noel García (@wolfwolker) • Joaquín Fernández Campo (@xocas__) • Miguel Vilata (@miguelvilata)
  3. 3. Where?
  4. 4. What is Digilant DSP: Demand Side Platform => programmatic advertising. We have a backend to configure ours RTB bidder(s) architecture. • A programmatic campaign can have thousands of parameters.
  5. 5. Long journey From monolithic sf1 (legacy , 8 years of development) to a SOA in sf2-3:
  6. 6. Requirements • API Rest • Auto Scalable (can be a huge huge demanding platform) • Symfony 2 • Easy to deploy
  7. 7. So?
  8. 8. Do not try this at home
  9. 9. Yes Symfony 2-3 Bundle: “A bundle is simply a structured set of files within a directory that implement a single feature. “ -- We can split services as bundles, and start here. This sounds weird?? Uncle Bob: “Don't leap into microservices just because it sounds cool. Segregate the system into jars using a plugin architecture first. If that's not sufficient, then consider introducing service boundaries at strategic points.”
  10. 10. Some Questions arose • One repo? One per service orchestrated with composer? • One repo, let’s split it later, and coordinate with composer later. (easier to develop) • One Db per service? One db for the whole project, with soft-relations between services? • One Db for the whole project, let’s split it later. (easier to develop??, careful with soft-relations, lost of referential integrity)
  11. 11. Our motto Let’s split it later And let’s start!!
  12. 12. Backend Services View Bundles
  13. 13. Yes, services bundles
  14. 14. Service- Machine We can create as many services-machine as we want. Depending on demand. We can cook them!! Fully elastic scalability. LineItem Service - Machine LineItem Core LineItem- Campaign - Machine LineItem Campaign Core
  15. 15. Cooking Process 1 Using ansistrano (ansible), in each deploy, we can select how many bundles a machine have. Machine A- Geo and Creatives Machine B- All services but Pixel
  16. 16. Cooking Process 2 We need to dynamically load, our “bundles-service” on deploy, our models, our routings, etc.. A lot of magic happens here! Compiler pass to the rescue!
  17. 17. Cooking Process 3 In our AppKernel.php. We have the LocateBundles (utility class) in a CoreBundle
  18. 18. Core Bundle We have a CoreBundle, that act as a glue, (Compiler passes) • Communication between services (Can be http- external, http-internal, process) We have a call Router. API-REST, that’s why http-internal or external • Some bussines event listeners (a filter for accounts, softdelete, audit db listener) • User-Permission Model
  19. 19. Models 1 In order to don’t get coupled to the persistence implementation (Doctrine), don’t use annotations for defining the model, map in an xml:
  20. 20. Models 2 We want to use our own folders: Base?? We will explain it later, we have an autogenerator of code.
  21. 21. Models 3 Compiler Pass to Load Models in our own folders. We pass through our bundles, and load models, in our folders. The key: DoctrineOrmMappingPass We also use an alias: LineItem:ThirdPartyData Geo:City ServiceName:Model
  22. 22. Others Compilers Passes Here we load our services (symfony) in each Bundle. Also Lists calls (api-rest list call, defaults limit per model, orderby etc..)
  23. 23. Others Compilers Passes II Load the routes per each bundle!
  24. 24. Controller Services GeoBundle/Resources/config/services.yml imports: - resource: ServicesControllers/alpha.yml We load versionable controllers (alpha, v1..) as services: Right now: alpha (Remember WIP?) Routes: /alpha/creative/* /current/creative/*
  25. 25. A lot of CRUD tables-controllers We have a lot of master- admin tables. We have a RestController for this purpose. Controversy: - We have a lot of classes child of this one. - Needs refactor in services!
  26. 26. 2nd part And now …. The funny part :)
  27. 27. Generator of code Once upon a time … We had time and we were youngs :) and we decide to invest time creating a code generator to make our life easier … you know ? developers ... this lazy race With a lot of database schemas per create we thought that was a good idea to convert this MWB files directly in code … and was a really nightmare ...
  28. 28. Code generator (AKA mwb-import) But … it worked MWB file it’s a ZIP xml sqlite etc .. unzip generate code with twig generate fixtures
  29. 29. Code generator (AKA mwb-import)
  30. 30. ApiDoc documentation generator document ! document ! document ! document ! document ! document !
  31. 31. ApiDoc documentation generator But not only generates documentation. Why don’t use annotations to generate automatic documentation of API routes ? There are a couple of bundles in the market that do this. Again … we thought that we can do better.
  32. 32. ApiDoc documentation generator /** * @ApiDocDescription("Create an Account") * @ApiDocMethod("post") * @ApiDocRoute("/account") * @ApiDocVersion("~") * @ApiDocSubdomain("account") * @ApiDocParam(name="maxBudgetValue",type="decimal",nullable=false,description="Account maxBudgetValue") * @ApiDocHeader(name="Authorization", placeholder="Authorization: Bearer {token}", type="string", nullable=false, description="mandatory token obtained in login check call") * @ApiDocReturnHeader(" * HTTP 200 OK * Cache-Control: no-cache * Content-Type: application/json * ") * @ApiDocReturnData(type="json", sample="{'id':'integer'}") */ public function createAction(Request $request)
  33. 33. Documentator Features: automatic creation of documentation in html format, including a sandbox to test API endpoints
  34. 34. Documentator
  35. 35. Documentator Features: automatic creation of documentation in html format, including a sandbox to test API endpoints - export to POSTMAN collection
  36. 36. Call Router How to make a call to a service that you even know where is ? LineItem Service - Machine LineItem Core LineItem- Campaign - Machine LineItem Campaign Core
  37. 37. Call Router How to call a controller method if you don’t know where exactly is ? Remember, we can deploy to n-servers … To solve that we created a CallRouter that makes the call internally (if the server has the service required) or makes the call external (guzzle) if the service is in another server.
  38. 38. Call Router try { // ... $route = $this->router->match($pathInfo); return $this->makeInternalCall($route['_controller'], $request); } catch (ResourceNotFoundException $e) { return $this->makeExternalCall($request->getMethod(), $subdomain, $pathInfo, $request->getContent()); }

×