Class: Orchestrator::Core::ModuleManager

Inherits:
Object
  • Object
show all
Defined in:
lib/orchestrator/core/module_manager.rb

Direct Known Subclasses

Device::Manager, Logic::Manager, Service::Manager

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(thread, klass, settings) ⇒ ModuleManager

Returns a new instance of ModuleManager.



4
5
6
7
8
9
10
11
12
13
14
15
# File 'lib/orchestrator/core/module_manager.rb', line 4

def initialize(thread, klass, settings)
    @thread = thread        # Libuv Loop
    @settings = settings    # Database model
    @klass = klass
    
    # Bit of a hack - should make testing pretty easy though
    @status = ::ThreadSafe::Cache.new
    @stattrak = @thread.observer
    @logger = ::Orchestrator::Logger.new(@thread, @settings)

    @updating = Mutex.new
end

Instance Attribute Details

#current_userObject

Returns the value of attribute current_user.



20
21
22
# File 'lib/orchestrator/core/module_manager.rb', line 20

def current_user
  @current_user
end

#instanceObject (readonly)

Returns the value of attribute instance.



18
19
20
# File 'lib/orchestrator/core/module_manager.rb', line 18

def instance
  @instance
end

#loggerObject (readonly)

Returns the value of attribute logger.



19
20
21
# File 'lib/orchestrator/core/module_manager.rb', line 19

def logger
  @logger
end

#settingsObject (readonly)

Returns the value of attribute settings.



18
19
20
# File 'lib/orchestrator/core/module_manager.rb', line 18

def settings
  @settings
end

#stattrakObject (readonly)

Returns the value of attribute stattrak.



19
20
21
# File 'lib/orchestrator/core/module_manager.rb', line 19

def stattrak
  @stattrak
end

#statusObject (readonly)

Returns the value of attribute status.



19
20
21
# File 'lib/orchestrator/core/module_manager.rb', line 19

def status
  @status
end

#threadObject (readonly)

Returns the value of attribute thread.



18
19
20
# File 'lib/orchestrator/core/module_manager.rb', line 18

def thread
  @thread
end

Instance Method Details

#add_subscription(sub) ⇒ Object

Called from subscribe and SystemProxy.subscribe always on the module thread



131
132
133
134
135
136
137
138
139
# File 'lib/orchestrator/core/module_manager.rb', line 131

def add_subscription(sub)
    if sub.is_a? ::Libuv::Q::Promise
        # Promise recursion?
        sub.then method(:add_subscription)
    else
        @subsciptions ||= Set.new
        @subsciptions.add sub
    end
end

#define_setting(name, value) ⇒ Object

Called from Core::Mixin on any thread

Settings updates are done on the thread pool We have to replace the structure as other threads may be reading from the old structure and the settings hash is not thread safe



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/orchestrator/core/module_manager.rb', line 175

def define_setting(name, value)
    defer = thread.defer
    thread.schedule do
        defer.resolve(thread.work(proc {
            mod = Orchestrator::Module.find(@settings.id)
            mod.settings[name] = value
            mod.save!
            mod
        }))
    end
    defer.promise.then do |db_model|
        @settings = db_model
        value # Don't leak direct access to the database model
    end
end

#get_schedulerObject



79
80
81
# File 'lib/orchestrator/core/module_manager.rb', line 79

def get_scheduler
    @scheduler ||= ::Orchestrator::Core::ScheduleProxy.new(@thread)
end

#get_system(name) ⇒ ::Orchestrator::Core::SystemProxy

This is called from Core::Mixin on the thread pool as the DB query will be blocking

NOTE

Couchbase does support non-blocking gets although I think this is simpler



87
88
89
90
# File 'lib/orchestrator/core/module_manager.rb', line 87

def get_system(name)
    id = ::Orchestrator::ControlSystem.bucket.get("sysname-#{name.downcase}", {quiet: true}) || name
    ::Orchestrator::Core::SystemProxy.new(@thread, id.to_sym, self)
end

#inspectObject

override the default inspect method This provides relevant information and won’t blow the stack on an error



194
195
196
# File 'lib/orchestrator/core/module_manager.rb', line 194

def inspect
    "#<#{self.class}:0x#{self.__id__.to_s(16)} @thread=#{@thread.inspect} running=#{!@instance.nil?} managing=#{@klass.to_s} id=#{@settings.id}>"
end

#reloaded(mod) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/orchestrator/core/module_manager.rb', line 64

def reloaded(mod)
    @thread.schedule do
        # pass in any updated settings
        @settings = mod

        if @instance.respond_to? :on_update, true
            begin
                @instance.__send__(:on_update)
            rescue => e
                @logger.print_error(e, 'error in module update callback')
            end
        end
    end
end

#setting(name) ⇒ Object

Called from Core::Mixin on any thread For Logics: instance -> system -> zones -> dependency For Device: instance -> dependency



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/orchestrator/core/module_manager.rb', line 144

def setting(name)
    res = @settings.settings[name]
    if res.nil?
        if @settings.control_system_id
            sys = System.get(@settings.control_system_id)
            res = sys.settings[name]

            # Check if zones have the setting
            if res.nil?
                sys.zones.each do |zone|
                    res = zone.settings[name]
                    return res unless res.nil?
                end

                # Fallback to the dependency
                res = @settings.dependency.settings[name]
            end
        else
            # Fallback to the dependency
            res = @settings.dependency.settings[name]
        end
    end
    res
end

#startObject



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/orchestrator/core/module_manager.rb', line 45

def start
    return true unless @instance.nil?
    config = self
    @instance = @klass.new
    @instance.instance_eval { @__config__ = config }
    if @instance.respond_to? :on_load, true
        begin
            @instance.__send__(:on_load)
        rescue => e
            @logger.print_error(e, 'error in module load callback')
        end
    end
    update_running_status(true)
    true # for REST API
rescue => e
    @logger.print_error(e, 'module failed to start')
    false
end

#stopObject

Should always be called on the module thread



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/orchestrator/core/module_manager.rb', line 24

def stop
    return if @instance.nil?
    begin
        if @instance.respond_to? :on_unload, true
            @instance.__send__(:on_unload)
        end
    rescue => e
        @logger.print_error(e, 'error in module unload callback')
    ensure
        # Clean up
        @instance = nil
        @scheduler.clear if @scheduler
        if @subsciptions
            unsub = @stattrak.method(:unsubscribe)
            @subsciptions.each &unsub
            @subsciptions = nil
        end
        update_running_status(false)
    end
end

#subscribe(status, callback) ⇒ Object

Subscribe to status updates from status in the same module Called from Core::Mixin always on the module thread



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/orchestrator/core/module_manager.rb', line 107

def subscribe(status, callback)
    sub = @stattrak.subscribe({
        on_thread: @thread,
        callback: callback,
        status: status.to_sym,
        mod_id: @settings.id.to_sym,
        mod: self
    })
    add_subscription sub
    sub
end

#trak(name, value) ⇒ Object

Called from Core::Mixin - thread safe



93
94
95
96
97
98
99
100
101
102
103
# File 'lib/orchestrator/core/module_manager.rb', line 93

def trak(name, value)
    if @status[name] != value
        @status[name] = value

        # Allows status to be updated in workers
        # For the most part this will run straight away
        @thread.schedule do
            @stattrak.update(@settings.id.to_sym, name, value)
        end
    end
end

#unsubscribe(sub) ⇒ Object

Called from Core::Mixin always on the module thread



120
121
122
123
124
125
126
127
128
# File 'lib/orchestrator/core/module_manager.rb', line 120

def unsubscribe(sub)
    if sub.is_a? ::Libuv::Q::Promise
        # Promise recursion?
        sub.then method(:unsubscribe)
    else
        @subsciptions.delete sub
        @stattrak.unsubscribe(sub)
    end
end