Guest User

Untitled

a guest
Dec 13th, 2017
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.70 KB | None | 0 0
  1. # Caching in OfferProvider
  2.  
  3. - Why? - To improve performance (that is not call db an each provider request).
  4. - Where? - At the point of fething data from `OfferProvider` component (repositories).
  5. - How? - By using `Rails.cache#fetch`
  6.  
  7. ## Introduction
  8.  
  9. Why we don't like caching?
  10.  
  11. - cache keys? (we don't know how to name the keys)
  12. - cache invalidaiton? (we are fraid that after updating record, app will still serve old data)
  13. - cache size? (ActiveRecord models when serialized can grow of of controll)
  14.  
  15. That 3 points above we makes caching not a trivial task and IMHO that's why developers tend to avoid it.
  16.  
  17. Hovewer, because in `OfferProvider`:
  18.  
  19. - we don't write do db in any other way than throught repository
  20. - we don't read in any other way than throught repository
  21. - and we use dry-structs as data containers (not AR models)
  22.  
  23. In other words, because we encapsulate data access by Repository - cache becomes simple to manage.
  24.  
  25. In next sections I'd like to present my proposal.
  26.  
  27. ### Repositories encapsulates data access (reads and writes to db)
  28.  
  29. __Read:__
  30.  
  31. ```ruby
  32. def find(id, provider_id)
  33. build_from_record(find_record(id, provider_id))
  34. end
  35.  
  36. # with cache:
  37. def find(id, provider_id)
  38. Rails.cache.fetch('cache_key_will_be_described_later') do
  39. build_from_record(find_record(id, provider_id))
  40. end
  41. end
  42. ```
  43.  
  44. __Write:__
  45.  
  46. ```ruby
  47. def update(provider_id:, id:, changeset:)
  48. record = find_record(id, provider_id)
  49. record.update!(update_query_params(changeset.to_h))
  50.  
  51. build_from_record(record)
  52. end
  53.  
  54. # with cache
  55. def update(provider_id:, id:, changeset:)
  56. record = find_record(id, provider_id)
  57. record.update!(update_query_params(changeset.to_h))
  58.  
  59. invalidate_cache(provider_id)
  60. build_from_record(record)
  61. end
  62. ```
  63.  
  64. ### Repositories methods and their parameters define the cache key.
  65.  
  66. Cache key will depend on methods parameters.
  67.  
  68. eg. for:
  69.  
  70. `find(id, provider_id)`
  71.  
  72. cache key: "providers_#{provider_id}_#{id}_find"
  73.  
  74. ### Repositories modify data
  75.  
  76. Currently we have 3 methods in OfferProvider repository (create, update, delete).
  77. That simplifies cache invalidation.
  78. Cache will be invalidated only in these methods.
  79.  
  80. ### We control cache size thanks to dry-stucts
  81.  
  82. How data are stored in cache?
  83. Data is serialized on write to cache and deserialized on reading from cache.
  84. In our cache we will cache our dry-structs, so it's lightweight and we completely controll it.
  85.  
  86. ## Example
  87.  
  88. ```
  89. @startuml
  90. "Controller/Service" -> Repository : find_by(a, b)
  91. Repository -> Record : find_by(a, b)
  92. Repository <-- Record : record
  93. Repository -> Factory : build_from_record(record)
  94. Repository <-- Factory : entity
  95. "Controller/Service" <-- Repository : entity
  96.  
  97. box "Persistence layer" #LightBlue
  98. participant Repository
  99. participant Record
  100. participant Factory
  101. end box
  102. @enduml
  103. ```
Add Comment
Please, Sign In to add comment