source: branches/CEDMA-Refactoring-Ticket419/HeuristicLab.Grid/GridClient.cs @ 1130

Last change on this file since 1130 was 1130, checked in by gkronber, 12 years ago
  • re-enabled security for all WCF services;
  • debugged rdf queries
  • added tracing for WCF services
  • implemented simple version of quality based dispatching
  • extended ontology to include a number of predefined model-attributes (quality, size, evaluated solutions etc.)

ticket: #419 (Refactor CEDMA plugins)

File size: 7.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21using System;
22using System.Collections.Generic;
23using System.Linq;
24using System.Text;
25using System.ServiceModel;
26using System.Diagnostics;
27using System.Threading;
28using HeuristicLab.PluginInfrastructure;
29
30namespace HeuristicLab.Grid {
31  class GridClient {
32    private string uri;
33    private ChannelFactory<IEngineStore> factory;
34    private System.Timers.Timer fetchOperationTimer;
35    private IEngineStore engineStore;
36    private object connectionLock = new object();
37    private const int CONNECTION_RETRY_TIMEOUT_SEC = 10;
38    private const int MAX_RETRIES = 10;
39
40    public bool Waiting {
41      get {
42        return !executing && !stopped;
43      }
44    }
45
46    private bool executing;
47    public bool Executing {
48      get {
49        return executing;
50      }
51    }
52
53    private bool stopped;
54    public bool Stopped {
55      get {
56        return stopped;
57      }
58    }
59
60    private string statusMessage = "";
61    public string StatusMessage {
62      get {
63        return statusMessage;
64      }
65    }
66
67    internal GridClient() {
68      fetchOperationTimer = new System.Timers.Timer();
69      fetchOperationTimer.Interval = 200;
70      fetchOperationTimer.Elapsed += new System.Timers.ElapsedEventHandler(fetchOperationTimer_Elapsed);
71      stopped = true;
72    }
73
74    internal void Start(string uri) {
75      try {
76        this.uri = uri;
77        ResetConnection();
78        fetchOperationTimer.Start();
79        stopped = false;
80      } catch(CommunicationException ex) {
81        statusMessage = DateTime.Now.ToShortTimeString()+": Exception while connecting to the server: " + ex.Message;
82        fetchOperationTimer.Stop();
83      }
84    }
85
86    internal void Stop() {
87      fetchOperationTimer.Stop();
88      lock(connectionLock) {
89        if(factory.State == CommunicationState.Opened || factory.State == CommunicationState.Opening) {
90          IAsyncResult closeResult = factory.BeginClose(null, null);
91          factory.EndClose(closeResult);
92        }
93      }
94      stopped = true;
95    }
96
97    private void ResetConnection() {
98      Trace.TraceInformation("Reset connection in GridClient");
99      NetTcpBinding binding = new NetTcpBinding();
100      binding.MaxReceivedMessageSize = 100000000; // 100Mbytes
101      binding.ReaderQuotas.MaxStringContentLength = 100000000; // also 100M chars
102      binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
103      factory = new ChannelFactory<IEngineStore>(binding);
104      engineStore = factory.CreateChannel(new EndpointAddress(uri));
105    }
106
107    private void fetchOperationTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
108      try {
109        byte[] engineXml = null;
110        Guid currentGuid;
111        // first stop the timer!
112        fetchOperationTimer.Stop();
113        bool gotEngine = false;
114        lock(connectionLock) {
115          if(stopped) return;
116          try {
117            gotEngine = engineStore.TryTakeEngine(out currentGuid, out engineXml);
118          } catch(TimeoutException) {
119            ChangeStatusMessage("TimeoutException while trying to get an engine");
120            currentGuid = Guid.Empty;
121            // timeout -> just start the timer again
122            fetchOperationTimer.Interval = 5000;
123            fetchOperationTimer.Start();
124          } catch(CommunicationException) {
125            ChangeStatusMessage("CommunicationException while trying to get an engine");
126            // connection problem -> reset connection and start the timer again
127            ResetConnection();
128            currentGuid = Guid.Empty;
129            fetchOperationTimer.Interval = 5000;
130            fetchOperationTimer.Start();
131          }
132        }
133        // got engine from server and user didn't press stop -> execute the engine
134        if(gotEngine && !stopped) {
135          executing = true;
136          AppDomain engineDomain = PluginManager.Manager.CreateAndInitAppDomain("Engine domain");
137          Type engineRunnerType = typeof(EngineRunner);
138         
139          EngineRunner runner = (EngineRunner)engineDomain.CreateInstanceAndUnwrap(engineRunnerType.Assembly.GetName().Name, engineRunnerType.FullName);
140          byte[] resultXml = runner.Execute(engineXml);
141          bool success = false;
142          int retries = 0;
143          do {
144            lock(connectionLock) {
145              if(!stopped) {
146                try {
147                  engineStore.StoreResult(currentGuid, resultXml);
148                  success = true;
149                } catch(TimeoutException) {
150                  ChangeStatusMessage("TimeoutException while trying to store the result of an engine");
151                  success = false;
152                  retries++;
153                  Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
154                } catch(CommunicationException) {
155                  ChangeStatusMessage("CommunicationException while trying to store the result of an engine");
156                  ResetConnection();
157                  success = false;
158                  retries++;
159                  Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
160                }
161              }
162            }
163          } while(!stopped && !success && retries < MAX_RETRIES);
164          // dispose the AppDomain that was created to run the job
165          AppDomain.Unload(engineDomain);
166          executing = false;
167          // ok if we could store the result it's probable that the server can send us another engine use a small time-interval
168          if(success)
169            fetchOperationTimer.Interval = 100;
170          else fetchOperationTimer.Interval = 30000; // if there were problems -> sleep for a longer time
171          // clear state
172          currentGuid = Guid.Empty;
173          // start the timer
174          fetchOperationTimer.Start();
175        } else {
176          // ok we didn't get engine -> if the user didn't press stop this means that the server doesn't have engines for us
177          // if the user pressed stop we must not start the timer
178          if(!stopped) {
179            // start the timer again
180            fetchOperationTimer.Interval = 5000;
181            fetchOperationTimer.Start();
182          }
183        }
184      } catch(Exception ex) {
185        // in case something goes wrong when creating / unloading the AppDomain
186        ChangeStatusMessage("Uncaught exception " + ex.Message);
187        Stop();
188      }
189    }
190
191    private void ChangeStatusMessage(string msg) {
192      Trace.TraceWarning(msg);
193      statusMessage = DateTime.Now.ToShortTimeString() + ": " + msg;
194    }
195  }
196}
Note: See TracBrowser for help on using the repository browser.