diff --git a/Gemfile b/Gemfile index 92ff520..c8be050 100644 --- a/Gemfile +++ b/Gemfile @@ -20,3 +20,5 @@ gem "syntax_tree" gem "activerecord" gem "sequel" gem "connection_pool" +gem "rails_event_store" +gem "rails" diff --git a/Gemfile.lock b/Gemfile.lock index d914ce1..d13e245 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,12 +7,67 @@ PATH GEM remote: https://rubygems.org/ specs: + action_text-trix (2.1.19) + railties + actioncable (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + zeitwerk (~> 2.6) + actionmailbox (8.1.3) + actionpack (= 8.1.3) + activejob (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) + mail (>= 2.8.0) + actionmailer (8.1.3) + actionpack (= 8.1.3) + actionview (= 8.1.3) + activejob (= 8.1.3) + activesupport (= 8.1.3) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (8.1.3) + actionview (= 8.1.3) + activesupport (= 8.1.3) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (8.1.3) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (8.1.3) + activesupport (= 8.1.3) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (8.1.3) + activesupport (= 8.1.3) + globalid (>= 0.3.6) activemodel (8.1.3) activesupport (= 8.1.3) activerecord (8.1.3) activemodel (= 8.1.3) activesupport (= 8.1.3) timeout (>= 0.4.0) + activestorage (8.1.3) + actionpack (= 8.1.3) + activejob (= 8.1.3) + activerecord (= 8.1.3) + activesupport (= 8.1.3) + marcel (~> 1.0) activesupport (8.1.3) base64 bigdecimal @@ -26,16 +81,25 @@ GEM securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) + aggregate_root (2.19.1) + ruby_event_store (= 2.19.1) + arkency-command_bus (0.4.1) + concurrent-ruby ast (2.4.3) base64 (0.3.0) benchmark (0.5.0) bigdecimal (4.1.2) + builder (3.3.0) concurrent-ruby (1.3.6) connection_pool (3.0.2) + crass (1.0.6) date (3.5.1) diff-lcs (2.0.0) drb (2.2.3) erb (6.0.4) + erubi (1.13.1) + globalid (1.3.0) + activesupport (>= 6.1) i18n (1.14.8) concurrent-ruby (~> 1.0) io-console (0.8.2) @@ -46,8 +110,19 @@ GEM reline (>= 0.4.2) json (2.19.5) logger (1.7.0) + loofah (2.25.1) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) m (1.7.0) rake + mail (2.9.0) + logger + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.2.1) + mini_mime (1.1.5) minitest (6.0.6) drb (~> 2.0) prism (~> 1.5) @@ -66,6 +141,22 @@ GEM mutant (= 0.16.3) mutex_m (~> 0.2) mutex_m (0.3.0) + net-imap (0.6.4) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.5.1) + net-protocol + nio4r (2.7.5) + nokogiri (1.19.3-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.3-arm64-darwin) + racc (~> 1.4) + nokogiri (1.19.3-x86_64-linux-gnu) + racc (~> 1.4) parser (3.3.11.1) ast (~> 2.4.1) racc @@ -88,6 +179,55 @@ GEM date stringio racc (1.8.1) + rack (3.2.6) + rack-session (2.1.2) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rackup (2.3.1) + rack (>= 3) + rails (8.1.3) + actioncable (= 8.1.3) + actionmailbox (= 8.1.3) + actionmailer (= 8.1.3) + actionpack (= 8.1.3) + actiontext (= 8.1.3) + actionview (= 8.1.3) + activejob (= 8.1.3) + activemodel (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) + bundler (>= 1.15.0) + railties (= 8.1.3) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + rails_event_store (2.19.1) + activejob (>= 6.0) + activemodel (>= 6.0) + activesupport (>= 6.0) + aggregate_root (= 2.19.1) + arkency-command_bus (>= 0.4) + rails_event_store_active_record (= 2.19.1) + ruby_event_store (= 2.19.1) + ruby_event_store-browser (= 2.19.1) + rails_event_store_active_record (2.19.1) + ruby_event_store-active_record (= 2.19.1) + railties (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) rake (13.4.2) rdoc (7.2.0) erb @@ -96,6 +236,14 @@ GEM regexp_parser (2.12.0) reline (0.6.3) io-console (~> 0.5) + ruby_event_store (2.19.1) + concurrent-ruby (~> 1.0, >= 1.1.6) + ruby_event_store-active_record (2.19.1) + activerecord (>= 6.0) + ruby_event_store (= 2.19.1) + ruby_event_store-browser (2.19.1) + rack + ruby_event_store (= 2.19.1) securerandom (0.4.1) sequel (5.104.0) bigdecimal @@ -103,6 +251,7 @@ GEM stringio (3.2.0) syntax_tree (6.3.0) prettier_print (>= 1.2.0) + thor (1.5.0) timeout (0.6.1) tsort (0.2.0) tzinfo (2.0.6) @@ -112,6 +261,12 @@ GEM parser (>= 3.3.0) prism (>= 1.5.1) uri (1.1.1) + useragent (0.16.11) + websocket-driver (0.8.0) + base64 + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.8.1) PLATFORMS aarch64-linux @@ -132,38 +287,67 @@ DEPENDENCIES minitest-stub-const mutant-minitest pg-ephemeral + rails + rails_event_store rake sequel syntax_tree CHECKSUMS + action_text-trix (2.1.19) sha256=7012f59421009cf284aa651294896414d653a61a2417c9b8714c8476d2f74009 + actioncable (8.1.3) sha256=e5bc7f75e44e6a22de29c4f43176927c3a9ce4824464b74ed18d8226e75a80f0 + actionmailbox (8.1.3) sha256=df7da474eaa0e70df4ed5a6fef66eb3b3b0f2dbf7f14518deee8d77f1b4aae59 + actionmailer (8.1.3) sha256=831f724891bb70d0aaa4d76581a6321124b6a752cb655c9346aae5479318448d + actionpack (8.1.3) sha256=af998cae4d47c5d581a2cc363b5c77eb718b7c4b45748d81b1887b25621c29a3 + actiontext (8.1.3) sha256=d291019c00e1ea9e6463011fa214f6081a56d7b9a1d224e7d3f6384c1dafc7d2 + actionview (8.1.3) sha256=1347c88c7f3edb38100c5ce0e9fb5e62d7755f3edc1b61cce2eb0b2c6ea2fd5d + activejob (8.1.3) sha256=a149b1766aa8204c3c3da7309e4becd40fcd5529c348cffbf6c9b16b565fe8d3 activemodel (8.1.3) sha256=90c05cbe4cef3649b8f79f13016191ea94c4525ce4a5c0fb7ef909c4b91c8219 activerecord (8.1.3) sha256=8003be7b2466ba0a2a670e603eeb0a61dd66058fccecfc49901e775260ac70ab + activestorage (8.1.3) sha256=0564ce9309143951a67615e1bb4e090ee54b8befed417133cae614479b46384d activesupport (8.1.3) sha256=21a5e0dfbd4c3ddd9e1317ec6a4d782fa226e7867dc70b0743acda81a1dca20e + aggregate_root (2.19.1) sha256=c387ee99a428944a08a96978e6ddf6ddb6ce93459d64955c0cb4f0766c110a2d + arkency-command_bus (0.4.1) sha256=8acac50774080ecf6828ba2f953f1ae293e80878efd555267dbd61b2ee764bde ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd + builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f bundler (4.0.11) sha256=5bcec0fb78302e48d02ee46f10ee6e6942be647ba5b44a6d1ddfda9a240ce785 concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a + crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0 diff-lcs (2.0.0) sha256=708a5d52ec2945b50f8f53a181174aa1ef2c496edf81c05957fe956dabb363d5 drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 en57 (0.1.0) erb (6.0.4) sha256=38e3803694be357fe2bfe312487c74beaf9fb4e5beb3e22498952fe1645b95d9 + erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 + globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11 i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5 io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3 json (2.19.5) sha256=218a18553e4801d579ca7e0f5bc72bafd776d7397238a1fb4e74db5b0a812c59 logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + loofah (2.25.1) sha256=d436c73dbd0c1147b16c4a41db097942d217303e1f7728704b37e4df9f6d2e04 m (1.7.0) sha256=058f793da8150c51353cc59366ffae7774683e868bede3c78f81d920fb9d633a + mail (2.9.0) sha256=6fa6673ecd71c60c2d996260f9ee3dd387d4673b8169b502134659ece6d34941 + marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f + mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1 minitest-mock (5.27.0) sha256=7040ed7185417a966920987eaa6eaf1be4ea1fc5b25bb03ff4703f98564a55b0 minitest-stub-const (0.6) sha256=b39f34dd6b8e7045fcc36820083aceaa68075318e4c4f365b12f11bd5f34b279 mutant (0.16.3) sha256=7e10fb09b80a78d82f8e38283fc1e4d562cbb1392451e2a21611ea2bc44b5023 mutant-minitest (0.16.3) sha256=504d110c1bd503528a7e57a4f062960e571bba4e3939e4a66ddc0f75d2071d90 mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751 + net-imap (0.6.4) sha256=9a5598c67a3022c284d98430ef1d4948e7dbdb62596f61081ea8ca933270a02b + net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 + net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 + net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736 + nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 + nokogiri (1.19.3-aarch64-linux-gnu) sha256=46b89e5d7b9e844c2ee360794240c6ea2a4e6fa0c5892a4ed487db621224b639 + nokogiri (1.19.3-arm64-darwin) sha256=71b9bd424b1b7abc18b05052a1a3cfd3627abdca62be280854cc411791357e42 + nokogiri (1.19.3-x86_64-linux-gnu) sha256=2f5078620fe12e83669b5b17311b32532a8153d02eee7ad06948b926d6080976 parser (3.3.11.1) sha256=d17ace7aabe3e72c3cc94043714be27cc6f852f104d81aa284c2281aecc65d54 pg (1.6.3) sha256=1388d0563e13d2758c1089e35e973a3249e955c659592d10e5b77c468f628a99 pg (1.6.3-aarch64-linux) sha256=0698ad563e02383c27510b76bf7d4cd2de19cd1d16a5013f375dd473e4be72ea @@ -178,20 +362,38 @@ CHECKSUMS prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85 psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974 racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f + rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2 + rack-session (2.1.2) sha256=595434f8c0c3473ae7d7ac56ecda6cc6dfd9d37c0b2b5255330aa1576967ffe8 + rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463 + rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868 + rails (8.1.3) sha256=6d017ba5348c98fc909753a8169b21d44de14d2a0b92d140d1a966834c3c9cd3 + rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d + rails-html-sanitizer (1.7.0) sha256=28b145cceaf9cc214a9874feaa183c3acba036c9592b19886e0e45efc62b1e89 + rails_event_store (2.19.1) sha256=7e1d649958c65fee72cda4a50f271dc7e3e31503c9a48d1a15ad2ee5fdd84e10 + rails_event_store_active_record (2.19.1) sha256=e5ad7fe661ee802bbb144f9c39eceb16c9cf09d314605e6ef75cd7afcb76dfbf + railties (8.1.3) sha256=913eb0e0cb520aac687ffd74916bd726d48fa21f47833c6292576ef6a286de22 rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701 rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192 regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835 + ruby_event_store (2.19.1) sha256=2e5eb4da5dc822c7983d8b3346a92c0643f35825798bbdb8bdcebb78f5be76eb + ruby_event_store-active_record (2.19.1) sha256=f23b59183d4e310354bac53f83e7d165c22ab226503b88f313d491f39f727d3c + ruby_event_store-browser (2.19.1) sha256=8a0ccdb80c942a8abc4a2e872c3345fb98308a371f11b08dc73f4f1909bab694 securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 sequel (5.104.0) sha256=1521819b9204aa7f5c25b29fbb2a609ba3f6a82d2271f34f718e1169d31bf03e sorbet-runtime (0.6.13222) sha256=d064f7fc317e4c0ae4a4112588f390d28d60f7dcdd0df7772b0036fce86c28d1 stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1 syntax_tree (6.3.0) sha256=56e25a9692c798ec94c5442fe94c5e94af76bef91edc8bb02052cbdecf35f13d + thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b unparser (0.9.0) sha256=4331f174a73a23b69250b13d47da3794ed1449711ee0f9ed8947dc020ba76067 uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6 + useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844 + websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962 + websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241 + zeitwerk (2.8.1) sha256=1c85e0f28954d68cd16e575da37f26846f609b68d80b5942ccfd31030c2449d5 BUNDLED WITH 4.0.11 diff --git a/database.toml b/database.toml index a91f5eb..0b339c0 100644 --- a/database.toml +++ b/database.toml @@ -31,3 +31,16 @@ path = "db/schema/0.1.0.sql" [instances.concurrent-append-conflicting-tags.seeds.schema] type = "sql-file" path = "db/schema/0.1.0.sql" + +[instances.res-append-stream-any.seeds.schema] +type = "sql-file" +path = "db/seeds/res.sql" + +[instances.res-concurrent-append-non-conflicting-streams.seeds.schema] +type = "sql-file" +path = "db/seeds/res.sql" + +[instances.res-concurrent-append-conflicting-streams.seeds.schema] +type = "sql-file" +path = "db/seeds/res.sql" + diff --git a/db/seeds/res.sql b/db/seeds/res.sql new file mode 100644 index 0000000..4b9f824 --- /dev/null +++ b/db/seeds/res.sql @@ -0,0 +1,229 @@ +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.ar_internal_metadata ( + key character varying NOT NULL, + value character varying, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: event_store_events; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.event_store_events ( + id bigint NOT NULL, + event_id uuid NOT NULL, + event_type character varying NOT NULL, + metadata jsonb, + data jsonb NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + valid_at timestamp(6) without time zone +); + + +-- +-- Name: event_store_events_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.event_store_events_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: event_store_events_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.event_store_events_id_seq OWNED BY public.event_store_events.id; + + +-- +-- Name: event_store_events_in_streams; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.event_store_events_in_streams ( + id bigint NOT NULL, + stream character varying NOT NULL, + "position" integer, + event_id uuid NOT NULL, + created_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: event_store_events_in_streams_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.event_store_events_in_streams_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: event_store_events_in_streams_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.event_store_events_in_streams_id_seq OWNED BY public.event_store_events_in_streams.id; + + +-- +-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.schema_migrations ( + version character varying NOT NULL +); + + +-- +-- Name: event_store_events id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_store_events ALTER COLUMN id SET DEFAULT nextval('public.event_store_events_id_seq'::regclass); + + +-- +-- Name: event_store_events_in_streams id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_store_events_in_streams ALTER COLUMN id SET DEFAULT nextval('public.event_store_events_in_streams_id_seq'::regclass); + + +-- +-- Name: ar_internal_metadata ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.ar_internal_metadata + ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); + + +-- +-- Name: event_store_events_in_streams event_store_events_in_streams_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_store_events_in_streams + ADD CONSTRAINT event_store_events_in_streams_pkey PRIMARY KEY (id); + + +-- +-- Name: event_store_events event_store_events_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_store_events + ADD CONSTRAINT event_store_events_pkey PRIMARY KEY (id); + + +-- +-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.schema_migrations + ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); + + +-- +-- Name: index_event_store_events_in_streams_on_created_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_store_events_in_streams_on_created_at ON public.event_store_events_in_streams USING btree (created_at); + + +-- +-- Name: index_event_store_events_in_streams_on_event_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_store_events_in_streams_on_event_id ON public.event_store_events_in_streams USING btree (event_id); + + +-- +-- Name: index_event_store_events_in_streams_on_stream_and_event_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_event_store_events_in_streams_on_stream_and_event_id ON public.event_store_events_in_streams USING btree (stream, event_id); + + +-- +-- Name: index_event_store_events_in_streams_on_stream_and_position; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_event_store_events_in_streams_on_stream_and_position ON public.event_store_events_in_streams USING btree (stream, "position"); + + +-- +-- Name: index_event_store_events_on_as_of; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_store_events_on_as_of ON public.event_store_events USING btree (COALESCE(valid_at, created_at)); + + +-- +-- Name: index_event_store_events_on_created_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_store_events_on_created_at ON public.event_store_events USING btree (created_at); + + +-- +-- Name: index_event_store_events_on_event_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_event_store_events_on_event_id ON public.event_store_events USING btree (event_id); + + +-- +-- Name: index_event_store_events_on_event_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_store_events_on_event_type ON public.event_store_events USING btree (event_type); + + +-- +-- Name: index_event_store_events_on_valid_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_store_events_on_valid_at ON public.event_store_events USING btree (valid_at); + + +-- +-- Name: event_store_events_in_streams fk_rails_c8d52b5857; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_store_events_in_streams + ADD CONSTRAINT fk_rails_c8d52b5857 FOREIGN KEY (event_id) REFERENCES public.event_store_events(event_id); + + +-- +-- PostgreSQL database dump complete +-- + +SET search_path TO "$user", public; + +INSERT INTO "schema_migrations" (version) VALUES +('20260521134825'); + diff --git a/lib/benchmark/res_append_stream_any.rb b/lib/benchmark/res_append_stream_any.rb new file mode 100644 index 0000000..d22751d --- /dev/null +++ b/lib/benchmark/res_append_stream_any.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require "active_record" +require "rails_event_store" + +module En57 + module Benchmark + class ResAppendStreamAny < Scenario + def initialize(...) + super + ActiveRecord::Base.establish_connection(@database_url) + @event_store = RailsEventStore::JSONClient.new + end + + private + + def call + type = "event_benchmarked" + tag = "writer:#{SecureRandom.hex(4)}" + events = + Array.new(@batch_size) do + RubyEventStore::Event.new(metadata: { event_type: type }) + end + + @measure.call do + @event_store.append(events, stream_name: tag, expected_version: :any) + end + end + + def verify = @event_store.read.each.to_a.size == total_runs * @batch_size + end + end +end diff --git a/lib/benchmark/res_concurrent_append_conflicting_streams.rb b/lib/benchmark/res_concurrent_append_conflicting_streams.rb new file mode 100644 index 0000000..c0de45c --- /dev/null +++ b/lib/benchmark/res_concurrent_append_conflicting_streams.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "active_record" +require "rails_event_store" + +module En57 + module Benchmark + class ResConcurrentAppendConflictingStreams < Scenario + def initialize(...) + super + ActiveRecord::Base.establish_connection(@database_url) + @event_store = RailsEventStore::JSONClient.new + end + + private + + def call + type = "event_benchmarked" + stream_name = "writer:#{SecureRandom.hex(4)}" + barrier = Concurrent::CyclicBarrier.new(@concurrency) + + concurrently(@concurrency) do + events = + Array.new(@batch_size) do + RubyEventStore::Event.new(metadata: { event_type: type }) + end + position = -1 + + barrier.wait + + @measure.call do + begin + @event_store.append( + events, + stream_name: stream_name, + expected_version: position, + ) + rescue RubyEventStore::WrongExpectedEventVersion + record_retry + position = @event_store.read.stream(stream_name).count - 1 + retry + end + end + end + end + + def verify = + @event_store.read.each.to_a.size == + total_runs * @concurrency * @batch_size + end + end +end diff --git a/lib/benchmark/res_concurrent_append_non_conflicting_streams.rb b/lib/benchmark/res_concurrent_append_non_conflicting_streams.rb new file mode 100644 index 0000000..38f58ed --- /dev/null +++ b/lib/benchmark/res_concurrent_append_non_conflicting_streams.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require "active_record" +require "rails_event_store" + +module En57 + module Benchmark + class ResConcurrentAppendNonConflictingStreams < Scenario + def initialize(...) + super + ActiveRecord::Base.establish_connection(@database_url) + @event_store = RailsEventStore::JSONClient.new + end + + private + + def call + type = "event_benchmarked" + barrier = Concurrent::CyclicBarrier.new(@concurrency) + + concurrently(@concurrency) do + tag = "writer:#{SecureRandom.hex(4)}" + @event_store.read.stream(tag).of_type(type) + events = + Array.new(@batch_size) do + RubyEventStore::Event.new(metadata: { event_type: type }) + end + + barrier.wait + + @measure.call do + @event_store.append( + events, + stream_name: tag, + expected_version: :none, + ) + end + end + end + + def verify = + @event_store.read.each.to_a.size == + total_runs * @concurrency * @batch_size + end + end +end diff --git a/lib/en57/benchmark.rb b/lib/en57/benchmark.rb index fb132b7..e877494 100644 --- a/lib/en57/benchmark.rb +++ b/lib/en57/benchmark.rb @@ -172,6 +172,9 @@ module En57 require_relative "../benchmark/concurrent_append_non_conflicting_tags" require_relative "../benchmark/concurrent_append_non_conflicting_tags_seeded" require_relative "../benchmark/concurrent_append_conflicting_tags" + require_relative "../benchmark/res_append_stream_any" + require_relative "../benchmark/res_concurrent_append_non_conflicting_streams" + require_relative "../benchmark/res_concurrent_append_conflicting_streams" class Runner def self.classic(runs: 50, names: nil) @@ -271,6 +274,47 @@ module En57 batch_size: 100, ) end, + "res-append-stream-any" => ->(database_url, warmup_runs, measure) do + ResAppendStreamAny.new( + name: "1x100 append, expected_version :any (RES)", + database_url:, + measure:, + warmup_runs:, + runs: runs * 10, + concurrency: 1, + batch_size: 100, + ) + end, + "res-concurrent-append-non-conflicting-streams" => ->( + database_url, + warmup_runs, + measure + ) do + ResConcurrentAppendNonConflictingStreams.new( + name: "10x100 concurrent append, non-conflicting streams (RES)", + database_url:, + measure:, + warmup_runs:, + runs:, + concurrency: 10, + batch_size: 100, + ) + end, + "res-concurrent-append-conflicting-streams" => ->( + database_url, + warmup_runs, + measure + ) do + ResConcurrentAppendConflictingStreams.new( + name: "10x100 concurrent append, conflicting streams (RES)", + database_url:, + measure:, + warmup_runs:, + runs:, + concurrency: 10, + batch_size: 100, + ) + end, } end diff --git a/test/test_benchmark.rb b/test/test_benchmark.rb index 9a1683c..8b230a1 100644 --- a/test/test_benchmark.rb +++ b/test/test_benchmark.rb @@ -342,6 +342,9 @@ module En57 concurrent-append-non-conflicting-tags concurrent-append-non-conflicting-tags-seeded concurrent-append-conflicting-tags + res-append-stream-any + res-concurrent-append-non-conflicting-streams + res-concurrent-append-conflicting-streams ], Runner.names, )