karafka-web 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +2 -8
  4. data/Gemfile.lock +1 -1
  5. data/lib/karafka/web/config.rb +0 -2
  6. data/lib/karafka/web/ui/base.rb +2 -6
  7. data/lib/karafka/web/ui/controllers/base.rb +0 -17
  8. data/lib/karafka/web/ui/controllers/cluster.rb +2 -5
  9. data/lib/karafka/web/ui/controllers/consumers.rb +1 -3
  10. data/lib/karafka/web/ui/controllers/errors.rb +6 -19
  11. data/lib/karafka/web/ui/controllers/jobs.rb +1 -3
  12. data/lib/karafka/web/ui/controllers/requests/params.rb +0 -10
  13. data/lib/karafka/web/ui/lib/paginate_array.rb +38 -0
  14. data/lib/karafka/web/ui/models/message.rb +38 -114
  15. data/lib/karafka/web/ui/models/status.rb +1 -3
  16. data/lib/karafka/web/ui/pro/app.rb +3 -11
  17. data/lib/karafka/web/ui/pro/controllers/consumers.rb +1 -3
  18. data/lib/karafka/web/ui/pro/controllers/dlq.rb +2 -1
  19. data/lib/karafka/web/ui/pro/controllers/errors.rb +10 -43
  20. data/lib/karafka/web/ui/pro/controllers/explorer.rb +7 -52
  21. data/lib/karafka/web/ui/pro/views/errors/_breadcrumbs.erb +6 -8
  22. data/lib/karafka/web/ui/pro/views/errors/_error.erb +1 -1
  23. data/lib/karafka/web/ui/pro/views/errors/_partition_option.erb +1 -1
  24. data/lib/karafka/web/ui/pro/views/errors/index.erb +56 -9
  25. data/lib/karafka/web/ui/pro/views/explorer/_breadcrumbs.erb +1 -1
  26. data/lib/karafka/web/ui/pro/views/explorer/_message.erb +2 -8
  27. data/lib/karafka/web/ui/pro/views/explorer/_partition_option.erb +1 -1
  28. data/lib/karafka/web/ui/pro/views/explorer/_topic.erb +1 -1
  29. data/lib/karafka/web/ui/pro/views/explorer/partition/_messages.erb +0 -1
  30. data/lib/karafka/web/ui/pro/views/explorer/partition.erb +1 -1
  31. data/lib/karafka/web/ui/pro/views/shared/_navigation.erb +1 -1
  32. data/lib/karafka/web/ui/views/cluster/_partition.erb +1 -1
  33. data/lib/karafka/web/ui/views/errors/_error.erb +1 -1
  34. data/lib/karafka/web/ui/views/shared/_pagination.erb +12 -16
  35. data/lib/karafka/web/version.rb +1 -1
  36. data.tar.gz.sig +0 -0
  37. metadata +2 -17
  38. metadata.gz.sig +0 -0
  39. data/lib/karafka/web/ui/lib/paginations/base.rb +0 -61
  40. data/lib/karafka/web/ui/lib/paginations/offset_based.rb +0 -96
  41. data/lib/karafka/web/ui/lib/paginations/page_based.rb +0 -70
  42. data/lib/karafka/web/ui/lib/paginations/paginators/arrays.rb +0 -33
  43. data/lib/karafka/web/ui/lib/paginations/paginators/base.rb +0 -23
  44. data/lib/karafka/web/ui/lib/paginations/paginators/partitions.rb +0 -52
  45. data/lib/karafka/web/ui/lib/paginations/paginators/sets.rb +0 -85
  46. data/lib/karafka/web/ui/lib/ttl_cache.rb +0 -74
  47. data/lib/karafka/web/ui/models/cluster_info.rb +0 -59
  48. data/lib/karafka/web/ui/pro/views/errors/_table.erb +0 -21
  49. data/lib/karafka/web/ui/pro/views/errors/_title_with_select.erb +0 -31
  50. data/lib/karafka/web/ui/pro/views/errors/partition.erb +0 -17
  51. data/lib/karafka/web/ui/pro/views/explorer/topic/_empty.erb +0 -3
  52. data/lib/karafka/web/ui/pro/views/explorer/topic/_limited.erb +0 -4
  53. data/lib/karafka/web/ui/pro/views/explorer/topic/_partitions.erb +0 -11
  54. data/lib/karafka/web/ui/pro/views/explorer/topic.erb +0 -49
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Lib
7
- module Paginations
8
- # Namespace for commands that build paginated resources based on the provided page
9
- module Paginators
10
- # A simple wrapper for paginating array related data structures
11
- # We call this with plural (same with `Sets`) to avoid confusion with Ruby classes
12
- class Arrays < Base
13
- class << self
14
- # @param array [Array] array we want to paginate
15
- # @param current_page [Integer] page we want to be on
16
- # @return [Array<Array, Boolean>] Array with two elements: first is the array with
17
- # data of the given page and second is a boolean flag with info if the elements we got
18
- # are from the last page
19
- def call(array, current_page)
20
- slices = array.each_slice(per_page).to_a
21
- current_data = slices[current_page - 1] || []
22
- last_page = !(slices.count >= current_page - 1 && current_data.size >= per_page)
23
-
24
- [current_data, last_page]
25
- end
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Lib
7
- module Paginations
8
- module Paginators
9
- # Base paginator
10
- class Base
11
- class << self
12
- # @return [Integer] number of elements per page
13
- def per_page
14
- ::Karafka::Web.config.ui.per_page
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Lib
7
- module Paginations
8
- module Paginators
9
- # Paginator for selecting proper range of partitions for each page
10
- # For topics with a lot of partitions we cannot get all the data efficiently, that
11
- # is why we limit number of partitions per page and reduce the operations
12
- # that way. This allows us to effectively display more while not having to fetch
13
- # more partitions then the number of messages per page.
14
- # In cases like this we distribute partitions evenly part of partitions on each of
15
- # the pages. This may become unreliable for partitions that are not evenly
16
- # distributed but this allows us to display data for as many partitions as we want
17
- # without overloading the system
18
- class Partitions < Base
19
- class << self
20
- # Computers the partitions slice, materialized page and the limitations status
21
- # for a given page
22
- # @param partitions_count [Integer] number of partitions for a given topic
23
- # @param current_page [Integer] current page
24
- # @return [Array<Array<Integer>, Integer, Boolean>] list of partitions that should
25
- # be active on a given page, materialized page for them and info if we had to
26
- # limit the partitions number on a given page
27
- def call(partitions_count, current_page)
28
- # How many "chunks" of partitions we will have
29
- slices_count = (partitions_count / per_page.to_f).ceil
30
- # How many partitions in a single slice should we have
31
- in_slice = (partitions_count / slices_count.to_f).ceil
32
- # Which "chunked" page do we want to get
33
- materialized_page = (current_page / slices_count.to_f).ceil
34
- # Which slice is the one we are operating on
35
- active_slice_index = (current_page - 1) % slices_count
36
- # All available slices so we can pick one that is active
37
- partitions_slices = (0...partitions_count).each_slice(in_slice).to_a
38
- # Select active partitions only
39
- active_partitions = partitions_slices[active_slice_index]
40
- # Are we limiting ourselves because of partition count
41
- limited = slices_count > 1
42
-
43
- [active_partitions, materialized_page, limited]
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Lib
7
- module Paginations
8
- module Paginators
9
- # Paginator that allows us to take several lists/sets and iterate over them in a
10
- # round-robin fashion.
11
- #
12
- # It does not have to iterate over all the elements from each set for higher pages
13
- # making it much more effective than the naive implementation.
14
- class Sets < Base
15
- class << self
16
- # @param counts [Array<Integer>] sets elements counts
17
- # @param current_page [Integer] page number
18
- # @return [Hash<Integer, Range>] hash with integer keys indicating the count
19
- # location and the range needed to be taken of elements (counting backwards) for
20
- # each partition
21
- def call(counts, current_page)
22
- return {} if current_page < 1
23
-
24
- lists = counts.dup.map.with_index { |el, i| [i, el] }
25
-
26
- curr_item_index = 0
27
- curr_list_index = 0
28
- items_to_skip_count = per_page * (current_page - 1)
29
-
30
- loop do
31
- lists_count = lists.length
32
- return {} if lists_count.zero?
33
-
34
- shortest_list_count = lists.map(&:last).min
35
- mover = (shortest_list_count - curr_item_index)
36
- items_we_are_considering_count = lists_count * mover
37
-
38
- if items_we_are_considering_count >= items_to_skip_count
39
- curr_item_index += items_to_skip_count / lists_count
40
- curr_list_index = items_to_skip_count % lists_count
41
- break
42
- else
43
- curr_item_index = shortest_list_count
44
- lists.delete_if { |x| x.last == shortest_list_count }
45
- items_to_skip_count -= items_we_are_considering_count
46
- end
47
- end
48
-
49
- page_items = []
50
- largest_list_count = lists.map(&:last).max
51
-
52
- while page_items.length < per_page && curr_item_index < largest_list_count
53
- curr_list = lists[curr_list_index]
54
-
55
- if curr_item_index < curr_list.last
56
- page_items << [curr_list.first, curr_item_index]
57
- end
58
-
59
- curr_list_index += 1
60
- if curr_list_index == lists.length
61
- curr_list_index = 0
62
- curr_item_index += 1
63
- end
64
- end
65
-
66
- hashed = Hash.new { |h, k| h[k] = [] }
67
-
68
- page_items.each do |el|
69
- hashed[el.first] << el.last
70
- end
71
-
72
- hashed.each do |key, value|
73
- hashed[key] = (value.first..value.last)
74
- end
75
-
76
- hashed
77
- end
78
- end
79
- end
80
- end
81
- end
82
- end
83
- end
84
- end
85
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- # Non info related extra components used in the UI
7
- module Lib
8
- # Ttl Cache for caching things in-memory
9
- # @note It **is** thread-safe
10
- class TtlCache
11
- include ::Karafka::Core::Helpers::Time
12
-
13
- # @param ttl [Integer] time in ms how long should this cache keep data
14
- def initialize(ttl)
15
- @ttl = ttl
16
- @times = {}
17
- @values = {}
18
- @mutex = Mutex.new
19
- end
20
-
21
- # Reads data from the cache
22
- #
23
- # @param key [String, Symbol] key for the cache read
24
- # @return [Object] anything that was cached
25
- def read(key)
26
- @mutex.synchronize do
27
- evict
28
- @values[key]
29
- end
30
- end
31
-
32
- # Writes to the cache
33
- #
34
- # @param key [String, Symbol] key for the cache
35
- # @param value [Object] value we want to cache
36
- # @return [Object] value we have written
37
- def write(key, value)
38
- @mutex.synchronize do
39
- @times[key] = monotonic_now + @ttl
40
- @values[key] = value
41
- end
42
- end
43
-
44
- # Reads from the cache and if value not present, will run the block and store its result
45
- # in the cache
46
- #
47
- # @param key [String, Symbol] key for the cache read
48
- # @return [Object] anything that was cached or yielded
49
- def fetch(key)
50
- @mutex.synchronize do
51
- evict
52
-
53
- return @values[key] if @values.key?(key)
54
-
55
- @values[key] = yield
56
- end
57
- end
58
-
59
- private
60
-
61
- # Removes expired elements from the cache
62
- def evict
63
- @times.each do |key, time|
64
- next if time >= monotonic_now
65
-
66
- @times.delete(key)
67
- @values.delete(key)
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Models
7
- # Wraps around the `Karafka::Admin#cluster_info` with caching and some additional aliases
8
- # so we can reference relevant information easily
9
- class ClusterInfo
10
- class << self
11
- # Gets us all the cluster metadata info
12
- #
13
- # @param cached [Boolean] should we use cached data (true by default)
14
- # @return [Rdkafka::Metadata] cluster metadata info
15
- def fetch(cached: true)
16
- cache = ::Karafka::Web.config.ui.cache
17
-
18
- cluster_info = cache.read(:cluster_info)
19
-
20
- if cluster_info.nil? || !cached
21
- cluster_info = cache.write(:cluster_info, Karafka::Admin.cluster_info)
22
- end
23
-
24
- cluster_info
25
- end
26
-
27
- # Returns us all the info about available topics from the cluster
28
- #
29
- # @param cached [Boolean] should we use cached data (true by default)
30
- # @return [Array<Ui::Models::Topic>] topics details
31
- def topics(cached: true)
32
- fetch(cached: cached)
33
- .topics
34
- .map { |topic| Topic.new(topic) }
35
- end
36
-
37
- # Fetches us details about particular topic
38
- #
39
- # @param topic_name [String] name of the topic we are looking for
40
- # @param cached [Boolean] should we use cached data (true by default)
41
- # @return [Ui::Models::Topic] topic details
42
- def topic(topic_name, cached: true)
43
- topics(cached: cached)
44
- .find { |topic_data| topic_data.topic_name == topic_name }
45
- .tap { |topic| topic || raise(Web::Errors::Ui::NotFoundError, topic_name) }
46
- end
47
-
48
- # @param topic_name [String] name of the topic we are looking for
49
- # @param cached [Boolean] should we use cached data (true by default)
50
- # @return [Integer] number of partitions in a given topic
51
- def partitions_count(topic_name, cached: true)
52
- topic(topic_name, cached: cached).partition_count
53
- end
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,21 +0,0 @@
1
- <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
2
- <thead>
3
- <tr class="align-middle">
4
- <th>Origin</th>
5
- <th>Process name</th>
6
- <th>Error</th>
7
- <th>Occurred at</th>
8
- <th></th>
9
- </tr>
10
- </thead>
11
-
12
- <tbody>
13
- <%==
14
- each_partial(
15
- @error_messages,
16
- 'errors/error',
17
- local: :error_msg
18
- )
19
- %>
20
- </tbody>
21
- </table>
@@ -1,31 +0,0 @@
1
- <div class="container mb-4">
2
- <div class="row">
3
- <div class="col">
4
- <h3>
5
- Errors
6
- </h3>
7
- </div>
8
-
9
- <div class="col">
10
- <div class="col-auto text-end">
11
- <label class="col-form-label">Partition</label>
12
- </div>
13
- </div>
14
-
15
- <div class="col pt-1 mb-0 pb-0">
16
- <div class="col-auto">
17
- <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
- <%==
19
- each_partial(
20
- [nil] + @partitions_count.times.to_a,
21
- 'errors/partition_option',
22
- local: :partition
23
- )
24
- %>
25
- </select>
26
- </div>
27
- </div>
28
- </div>
29
-
30
- <hr>
31
- </div>
@@ -1,17 +0,0 @@
1
- <%== partial('errors/title_with_select') %>
2
-
3
- <div class="container">
4
- <div class="row mb-5">
5
- <div class="col-sm-12">
6
- <%== partial('explorer/partition/watermark_offsets') %>
7
-
8
- <% if @watermark_offsets.empty? %>
9
- <%== partial 'errors/no_errors' %>
10
- <% elsif @watermark_offsets.cleaned? %>
11
- <%== partial 'errors/cleaned' %>
12
- <% else %>
13
- <%== partial 'errors/table' %>
14
- <% end %>
15
- </div>
16
- </div>
17
- </div>
@@ -1,3 +0,0 @@
1
- <div class="alert alert-info mt-4" role="alert">
2
- This topic is empty and does not contain any data in any of the partitions.
3
- </div>
@@ -1,4 +0,0 @@
1
- <div class="alert alert-info mt-4 mb-4" role="alert">
2
- Due to many partitions, only part of the data is visible on each page.
3
- Please navigate through the pages to view all data.
4
- </div>
@@ -1,11 +0,0 @@
1
- <p class="text-end mb-4">
2
- Partitions:
3
- <span class="badge bg-secondary mt-1 mb-1">
4
- total: <%= @partitions_count %>
5
- </span>
6
-
7
- <span class="badge bg-secondary mt-1 mb-1">
8
- visible:
9
- <%= [@active_partitions.first, @active_partitions.last].uniq.join(' to ') %>
10
- </span>
11
- </p>
@@ -1,49 +0,0 @@
1
- <div class="container mb-4">
2
- <div class="row">
3
- <div class="col">
4
- <h3>
5
- <%= @topic_id %>
6
- </h3>
7
- </div>
8
-
9
- <div class="col">
10
- <div class="col-auto text-end">
11
- <label class="col-form-label">Partition</label>
12
- </div>
13
- </div>
14
-
15
- <div class="col pt-1 mb-0 pb-0">
16
- <div class="col-auto">
17
- <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
- <%==
19
- each_partial(
20
- [nil] + @partitions_count.times.to_a,
21
- 'explorer/partition_option',
22
- local: :partition
23
- )
24
- %>
25
- </select>
26
- </div>
27
- </div>
28
- </div>
29
-
30
- <hr>
31
- </div>
32
-
33
- <div class="container">
34
- <div class="row mb-5">
35
- <div class="col-sm-12">
36
- <%== partial('explorer/topic/partitions') %>
37
-
38
- <% if @limited %>
39
- <%== partial('explorer/topic/limited') %>
40
- <% end %>
41
-
42
- <% if @messages.empty? && params.current_page == 1 %>
43
- <%== partial 'explorer/topic/empty' %>
44
- <% else %>
45
- <%== partial('explorer/partition/messages') %>
46
- <% end %>
47
- </div>
48
- </div>
49
- </div>