Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HL-3.2-MonoMigration/HeuristicLab.Grid/GridClient.cs @ 4136

Last change on this file since 4136 was 440, checked in by gkronber, 16 years ago
  • split the GridForm class into two classes GridForm and GridClient
  • added class EngineRunner to act as the bridge between the AppDomain where engines are executed and the main AppDomain of the client.
  • GridClient creates a new AppDomain for each engine and unloads it again when the engine is finished.

(ticket #230)

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;
28
29namespace HeuristicLab.Grid {
30  class GridClient {
31    private string uri;
32    private ChannelFactory<IEngineStore> factory;
33    private System.Timers.Timer fetchOperationTimer;
34    private IEngineStore engineStore;
35    private object connectionLock = new object();
36    private const int CONNECTION_RETRY_TIMEOUT_SEC = 10;
37    private const int MAX_RETRIES = 10;
38
39    public bool Waiting {
40      get {
41        return !executing && !stopped;
42      }
43    }
44
45    private bool executing;
46    public bool Executing {
47      get {
48        return executing;
49      }
50    }
51
52    private bool stopped;
53    public bool Stopped {
54      get {
55        return stopped;
56      }
57    }
58
59    private string statusMessage = "";
60    public string StatusMessage {
61      get {
62        return statusMessage;
63      }
64    }
65
66    internal GridClient() {
67      fetchOperationTimer = new System.Timers.Timer();
68      fetchOperationTimer.Interval = 200;
69      fetchOperationTimer.Elapsed += new System.Timers.ElapsedEventHandler(fetchOperationTimer_Elapsed);
70      stopped = true;
71    }
72
73    internal void Start(string uri) {
74      try {
75        this.uri = uri;
76        ResetConnection();
77        fetchOperationTimer.Start();
78        stopped = false;
79      } catch(CommunicationException ex) {
80        statusMessage = DateTime.Now.ToShortTimeString()+": Exception while connecting to the server: " + ex.Message;
81        fetchOperationTimer.Stop();
82      }
83    }
84
85    internal void Stop() {
86      fetchOperationTimer.Stop();
87      lock(connectionLock) {
88        if(factory.State == CommunicationState.Opened || factory.State == CommunicationState.Opening) {
89          IAsyncResult closeResult = factory.BeginClose(null, null);
90          factory.EndClose(closeResult);
91        }
92      }
93      stopped = true;
94    }
95
96    private void ResetConnection() {
97      Trace.TraceInformation("Reset connection in GridClient");
98      NetTcpBinding binding = new NetTcpBinding();
99      binding.MaxReceivedMessageSize = 100000000; // 100Mbytes
100      binding.ReaderQuotas.MaxStringContentLength = 100000000; // also 100M chars
101      binding.ReaderQuotas.MaxArrayLength = 100000000; // also 100M elements;
102      binding.Security.Mode = SecurityMode.None;
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 = AppDomain.CreateDomain("Engine domain", null, AppDomain.CurrentDomain.SetupInformation);
137          EngineRunner runner = (EngineRunner)engineDomain.CreateInstanceAndUnwrap("HeuristicLab.Grid", typeof(EngineRunner).FullName);
138          byte[] resultXml = runner.Execute(engineXml);
139          bool success = false;
140          int retries = 0;
141          do {
142            lock(connectionLock) {
143              if(!stopped) {
144                try {
145                  engineStore.StoreResult(currentGuid, resultXml);
146                  success = true;
147                } catch(TimeoutException) {
148                  ChangeStatusMessage("TimeoutException while trying to store the result of an engine");
149                  success = false;
150                  retries++;
151                  Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
152                } catch(CommunicationException) {
153                  ChangeStatusMessage("CommunicationException while trying to store the result of an engine");
154                  ResetConnection();
155                  success = false;
156                  retries++;
157                  Thread.Sleep(TimeSpan.FromSeconds(CONNECTION_RETRY_TIMEOUT_SEC));
158                }
159              }
160            }
161          } while(!stopped && !success && retries < MAX_RETRIES);
162          // dispose the AppDomain that was created to run the job
163          AppDomain.Unload(engineDomain);
164          executing = false;
165          // ok if we could store the result it's probable that the server can send us another engine use a small time-interval
166          if(success)
167            fetchOperationTimer.Interval = 100;
168          else fetchOperationTimer.Interval = 30000; // if there were problems -> sleep for a longer time
169          // clear state
170          currentGuid = Guid.Empty;
171          // start the timer
172          fetchOperationTimer.Start();
173        } else {
174          // ok we didn't get engine -> if the user didn't press stop this means that the server doesn't have engines for us
175          // if the user pressed stop we must not start the timer
176          if(!stopped) {
177            // start the timer again
178            fetchOperationTimer.Interval = 5000;
179            fetchOperationTimer.Start();
180          }
181        }
182      } catch(Exception ex) {
183        // in case something goes wrong when creating / unloading the AppDomain
184        ChangeStatusMessage("Uncaught exception " + ex.Message);
185        Stop();
186      }
187    }
188
189    private void ChangeStatusMessage(string msg) {
190      Trace.TraceWarning(msg);
191      statusMessage = DateTime.Now.ToShortTimeString() + ": " + msg;
192    }
193  }
194}
Note: See TracBrowser for help on using the repository browser.