-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathconcurrent_execution.rb
81 lines (69 loc) · 4.05 KB
/
concurrent_execution.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# (c) Copyright 2017 Hewlett Packard Enterprise Development LP
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
require_relative '_client' # Gives access to @client
# Some of the tasks that can be performed using this library take quite a bit of time; after all,
# we are dealing with physical infrastructure. This example file shows how to take advantage
# of native Ruby features that enable you to run tasks concurrently. Note that this is a more
# advanced topic, so if you're new to Ruby, you may want to familiarize yourself with Ruby threads
# before jumping in. Also, please read the notes below about considerations that should be taken
# when using threads.
# Example: Power on all server hardware available in OneView.
# Powering on server hardware isn't necessarily a super long task, but
# doing this for 100s or 1000s of profiles will take a while if we do
# them one-at-a-time. For about 30 servers, doing them one-at-a-time
# in my environment took 360 seconds, but only 16 seconds concurrently.
# Here's how to use threads to power them all on concurrently:
servers = @client.get_all(:ServerHardware)
servers_to_power_on = servers.reject { |s| s['powerState'] == 'On' }
puts "Total hardware count: #{servers.size}"
puts "Hardware count to be powered on: #{servers_to_power_on.size}\n\n"
threads = [] # Used to keep track of all the threads
servers_to_power_on.each do |s|
threads << Thread.new do
puts "Powering on '#{s['name']}'..."
s.power_on
puts " Done powering on '#{s['name']}'"
end
end
threads.each(&:join)
puts 'Finished powering on all server hardware!'
# NOTE: There are some considerations to be taken when using threads:
# - Consider the number of threads you will be running at any one time. In the example
# above, if there are 100,000 servers, it will try to power them on all at once, which
# may bring OneView to it's knees or cause issues on your local machine (e.g., IO or network
# overload). If the number of threads is indeterminate (like above where we did a get_all),
# batch the tasks into more manageable groups. You may also want to use thread pools if you
# will be dealing with lots of threads and/or multiple batches.
# - Consider how you will handle exceptions within threads. In the example above, any exception
# will only be raised at the point the thread is joined. If you'd like to fail immediately on
# any thread exception, you can set the abort_on_exception property on the thread to true.
# - Consider resource dependencies and the linkages between them. For example, if you are
# creating a volume template and volume that relies on that template, you need to make sure
# that any tasks to create or update the template are finished before trying to create the volume.
# - Consider the operations you are doing on objects in threads, and whether or not thos operations
# are thread-safe. In general, you should not perform multiple actions on the same object at once.
# After reading those considerations, I might do something like this to power on my servers instead:
# This time I'll batch them into groups of 15. For that same 30 servers it takes 28 seconds.
servers_to_power_on.each_slice(15) do |s_batch|
threads = []
s_batch.each do |s|
threads << Thread.new do
puts "Powering on '#{s['name']}'..."
s.power_on
puts " Done powering on '#{s['name']}'"
end
end
threads.each(&:join)
puts "Done with batch of 15\n\n"
end
puts 'Finished powering on all server hardware!'
# There is still plenty to learn about threads that we didn't cover here, but hopefully this gives you
# a good place to start from.