У фінтэху нам часта даводзіцца апрацоўваць даволі масіўныя аб'ёмы дадзеных курсаў абмену валют. Мы атрымліваем дадзеныя з розных крыніц, і кожны з іх мае ўласнае ўяўленне аб тым, як экстрапаляваць значэння курсаў на заўтра, паслязаўтра, наступны месяц і нават наступныя тры гады. Калі б нехта ўмеў прадказваць курсы правільна, своечасова было б зачыняць бізнэс і проста тупа мяняць грошы туды-сюды. Некаторыя крыніцы карыстаюцца вялікім даверам, некаторыя пастаўляюць запар смецце, з рэдкімі украпінамі амаль правільных значэнняў, але затое для экзатычных пар. Наша праца заключаецца ў тым, каб прасеяць гэтыя дзясяткі тысяч значэнняў у секунду і вызначыць, што менавіта паказаць заказчыкам. Нам трэба адфільтраваць адзінае правільнае значэнне з тоны бруду і глею, як гэта робяць фламінга на абедзе.
Адмысловай адметнай прыкметай фламінга з'яўляецца масіўная выгінастая ўніз дзюба, з дапамогай якога яны фільтруюць ежу з вады ці глею.
- Вікі
Так нарадзілася бібліятэка Vela, якая захоўвае кэш стану для некалькіх значэнняў у зададзеных часавых інтэрвалах. Пад капотам яна на лёце адсейвае дрэнныя і састарэлыя дадзеныя, а таксама дае доступ да апошніх. N якія прайшлі валідацыю значэнням для кожнага ключа (пары валют, у нашым выпадку).
Дапусцім, мы збіраем курсы для трох пар валют. Найпростае вызначэнне Vela для захоўвання актуальнага стану будзе выглядаць неяк так:
defmodule Pairs do
use Vela,
eurusd: [sorter: &Kernel.<=/2],
eurgbp: [limit: 3, errors: 1],
eurcad: [validator: Pairs]
@behaviour Vela.Validator
@impl Vela.Validator
def valid?(:eurcad, rate), do: rate > 0
end
канфігурацыйны параметр threshold, І - апцыянальна - compare_by, гл. глаўку параўнанне ніжэй.
Калі валідацыя прайшла паспяхова, значэнне дадаецца ў спіс пад адпаведным ключом, у адваротным выпадку картэж {serie, value} адпраўляецца ў :__errors_.
параўнанне
Значэнні, якія захоўваюцца ў гэтых шэрагах, могуць быць любымі. Каб навучыць Vela іх параўноўваць, неабходна перадаць compare_by параметр у вызначэнне шэрагу (калі толькі значэння не могуць быць параўнаны стандартным Kernel.</2); гэты параметр павінен мець тып (Vela.value() -> number()). Па змаўчанні гэта проста & &1.
Таксама, у вызначэнне шэрагу можна перадаць параметр comparator для вылічэння значэнняў дэльт (min/max); напрыклад, перадаючы Date.diff/2 у якасці кампаратара, можна атрымаць правільныя дэльты для дат.
Іншым зручным спосабам працы з'яўляецца перадача параметра threshold, які вызначае максімальна дапушчальнае стаўленне новага значэння да {min, max} інтэрвалу. Паколькі ён зададзены ў працэнтах, праверка не выкарыстоўвае comparator, але ўсё яшчэ выкарыстоўвае compare_by. Напрыклад, каб паказаць парогавае значэнне для часу дат, неабходна паказаць compare_by: &DateTime.to_unix/1 (для атрымання цэлалікавага значэння) і threshold: 1, у выніку чаго новыя значэння будуць дазволеныя, толькі калі яны знаходзяцца ў ±band інтэрвале ад бягучых значэнняў.
Нарэшце, можна выкарыстоўваць Vela.equal?/2 для параўнання двух кэшаў. Калі значэння вызначаюць функцыю equal?/2 або compare/2, то гэтыя функцыі будуць выкарыстаны для параўнання, у адваротным выпадку мы тупа выкарыстоўваем ==/2.
Атрыманне значэнняў
Апрацоўка бягучага стану звычайна пачынаецца з выкліку Vela.purge/1, які прыбірае састарэлыя значэння (калі validator завязаны на timestamps). Затым можна выклікаць Vela.slice/1, якая верне keyword з імёнамі шэрагаў у якасці ключоў і першым, актуальнымі значэннямі.
Таксама можна скарыстацца get_in/2/pop_in/2 для нізкаўзроўневага доступу да значэнняў у кожным шэрагу.
Дадатак
Vela можа апынуцца надзвычай карыснай у якасці кэша часовых шэрагаў у стейце працэсу тыпу GenServer/Agent. Мы хочам ніколі не выкарыстоўваць састарэлыя значэння курсаў, і для гэтага мы проста трымаем працэс са станам, апрацоўваным Vela, з валідатарам, паказаным ніжэй.
и Vela.purge/1 спакойна выдаляе ўсе састарэлыя значэння кожны раз, калі нам патрабуюцца дадзеныя. Для доступу да актуальных значэнняў мы проста выклікаем Vela.slice/1, а калі патрабуецца невялікая гісторыя па курсе (увесь шэраг цалкам), мы проста вяртаем яго - ужо адсартаваным - з праваліраванымі значэннямі.