프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

markus / ConvertService / ServiceBase / Markus.Service.Station / ServiceStation.cs @ ff4b1e6e

이력 | 보기 | 이력해설 | 다운로드 (14.8 KB)

1
using log4net;
2
using Markus.Service.Extensions;
3
using Markus.Service.Helper;
4
using Markus.Service.IWcfService;
5
using Markus.Service.WcfService;
6
using Salaros.Configuration;
7
using System;
8
using System.Collections.Generic;
9
using System.ComponentModel;
10
using System.Data;
11
using System.Diagnostics;
12
using System.Globalization;
13
using System.IO;
14
using System.Linq;
15
using System.Runtime.InteropServices;
16
using System.ServiceModel;
17
using System.ServiceProcess;
18
using System.Text;
19
using System.Threading.Tasks;
20
using System.Timers;
21
using static Markus.Service.Extensions.Encrypt;
22

    
23
namespace Markus.Service
24
{
25
    public partial class ServiceStation : ServiceBase
26
    {
27
        protected ILog logger = LogManager.GetLogger(typeof(ServiceStation));
28
        protected ServiceHost gWcfServiceHost;
29

    
30
        private static System.Timers.Timer timer;
31
        
32
        private int MultiProcessCount = 1;
33
        private string ServiceID;
34
        private List<SubStationServiceItem> StationServiceList;
35
        private List<string> StationServiceIDList;
36
        private Service.WcfClient.StationServiceAsync.StationServiceClient StationClient;
37
        private bool IsStation;
38

    
39
        private Uri gServiceHostAddress;
40

    
41
        private string MarkusDBConnectionString;
42
        private string DownloadTempFolder;
43
        private int MultiThreadMaxPages;
44
        private int MinFontSize;
45
        private int UseResolution;
46
        private bool CreateProcessWindow;
47
        private long ReleaseWorkMemory;
48

    
49
        private int SaveStatusInterval;
50

    
51
        private static bool IsReleaseItems;
52

    
53
        private List<string> RunProjectList = new List<string>();
54

    
55
        /// <summary>
56
        /// 프로세스 카운터 자주 람다식을 사용해서 list<int>로 함.
57
        /// </summary>
58
        private List<Int64> ProcessorAffinityList;
59

    
60
        private string configFileName;
61

    
62
        public ServiceStation()
63
        {
64
            InitializeComponent();
65
        }
66

    
67
        /// <summary>
68
        /// Config 파일 
69
        /// </summary>
70
        public void GetApplicationConfig()
71
        {
72
            try
73
            {
74
                ConfigParser config = null;
75

    
76
                try
77
                {
78
                    configFileName = $"{typeof(ServiceStation).Name}.ini";
79
                    config = ConfigHelper.AppConfig(this.configFileName);
80
                }
81
                catch (Exception)
82
                {
83
                    throw new Exception("Config Read Error.");
84
                }
85

    
86
                if (config != null)
87
                {
88
                    // CONVERT DATABASE 연결 문자열
89
                    MarkusDBConnectionString = AESEncrypter.Decrypt(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.MARKUS_CONNECTION_STRING));
90

    
91
                    IsStation = System.Convert.ToBoolean(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.IS_STATAION, "false"));
92

    
93
                    ServiceID = config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.SERVICE_ID, Guid.Empty.ToString());
94

    
95
                    if (IsStation)
96
                    {
97
                        var servicetList = config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.SERVICE_LIST, "");
98

    
99
                        if (!servicetList.IsNullOrEmpty())
100
                        {
101
                            StationServiceIDList = servicetList.Split(',').ToList();
102
                        }
103
                    }
104
                    else
105
                    {
106
                        var address = config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.STATAION_ADDRESS,"");
107

    
108
                        if (!address.IsNullOrEmpty())
109
                        {
110
                            BasicHttpBinding myBinding = new BasicHttpBinding();
111
                            EndpointAddress myEndpoint = new EndpointAddress(UriHelper.UriCreate(address));
112
                            StationClient = new WcfClient.StationServiceAsync.StationServiceClient(myBinding, myEndpoint);
113
                        }
114
                    }
115
                    
116
                    MultiProcessCount = System.Convert.ToInt16(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.CONVERT_SERVICE_PROCESS,"5"));
117

    
118
                    CreateProcessWindow = System.Convert.ToBoolean(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.CREATE_WINDOW, "false"));
119

    
120
                    // PDF 임시 다운로드 폴더
121
                    DownloadTempFolder = config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.DOWNLOAD_TEMP_FOLDER,"C:\\temp");
122

    
123
                    MultiThreadMaxPages = System.Convert.ToInt16(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.MULTI_TRHEAD_MAX_PAGE, "500"));
124

    
125
                    SaveStatusInterval = System.Convert.ToInt16(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.SAVE_STATUS_INTERVAL, "5"));
126

    
127
                    MinFontSize = System.Convert.ToInt16(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.MIN_FONT_SIZE, "10"));
128

    
129
                    UseResolution = System.Convert.ToInt16(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.USE_RESOLUTION, "0"));
130

    
131
                    var workingMemory = System.Convert.ToDouble(config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.RELEASE_WORK_MEMORY, "1.5"));
132

    
133
                    ReleaseWorkMemory = MathBytes.Bytes(workingMemory, DataSizeType.GB);
134

    
135
                    var projectList = config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.FITER_PROCECT,"");
136

    
137
                    if(!projectList.IsNullOrEmpty())
138
                    {
139
                        RunProjectList = projectList.Split(',').ToList();
140
                    }
141

    
142
                    // 서비스 ENDPOINT
143
                    // http://localhost/
144
                    var endpointName = config.GetValue(CONFIG_DEFINE.WCF_ENDPOINT, CONFIG_DEFINE.STATION_SERVICE_NAME);
145
                    var port = config.GetValue(CONFIG_DEFINE.WCF_ENDPOINT, CONFIG_DEFINE.STATION_PORT);
146

    
147
                    if (!string.IsNullOrWhiteSpace(endpointName) && port.IsNumber())
148
                    {
149
                        gServiceHostAddress = UriHelper.UriCreate($"http://localhost:{port}/{endpointName}");
150
                    }
151
                }
152
            }
153
            catch (Exception ex)
154
            {
155
                throw new Exception("ApplicationConfig ", ex);
156
            }
157
        }
158

    
159
        protected override void OnStart(string[] args)
160
        {
161
            try
162
            {
163
                StartService();
164
            }
165
            catch (Exception ex)
166
            {
167
                logger.Error("ServiceStation Start Error - ", ex);
168
            }
169
        }
170

    
171
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
172
        {
173
     
174
            System.Diagnostics.Debug.WriteLine("timer : " + e.SignalTime);
175
            try
176
            {
177
                if (!IsReleaseItems)
178
                {
179
                    ReleaseItems();
180
                }
181

    
182
                logger.Info("StationService Info");
183
            }
184
            catch (Exception ex)
185
            {
186
                logger.Error("Timer Error " ,ex);
187
            }
188

    
189
            System.Threading.Thread.SpinWait(1000);
190

    
191
            timer.Start();
192
        }
193

    
194
        /// <summary>
195
        /// alivequeue와 process를 비교하여 정리하고
196
        /// 대기중인 아이템을 분배한다.
197
        /// </summary>
198
        private void ReleaseItems()
199
        {
200
            try
201
            {
202
                IsReleaseItems = true;
203

    
204
                CleanUpAliveQueueItems();
205

    
206
                if (IsStation)
207
                {
208
                    if (IsDataBaseWaitingList(1))
209
                    {
210
                        System.Diagnostics.Debug.WriteLine("ReleaseItems start");
211
                        ReflashSubService();
212
                        CleanUpDataBaseItems();
213
                        setDataBaseWaitingList();
214
                        System.Diagnostics.Debug.WriteLine("ReleaseItems end");
215
                    }
216
                }
217
            }
218
            catch (Exception ex)
219
            {
220
                logger.Error("get Wating Item error", ex);
221
            }
222

    
223
            IsReleaseItems = false;
224
        }
225

    
226
        /// <summary>
227
        /// System.Diagnostics.Process의 ProcessorAffinity Core 선호도를 위한 초기화
228
        /// 설정된 MultiProcessCount에 대해서 프로세스의 코어의 선호도를 지정 한다.
229
        /// 코어의 선택은 비트로 이루어 진다.
230
        /// 8코어에서 1번 코어 00000001
231
        /// 8코어에서 1번 3번 코어 00000101
232
        /// 8코어에서 1번 3번 코어 00000101
233
        /// 8코어에서 1,2,3 선택   00000111
234
        /// https://dotnetgalactics.wordpress.com/2009/10/20/how-to-set-the-processor-affinity-programatically/
235
        /// </summary>
236
        private void ProcessorAffinityInit()
237
        {
238
            ProcessorAffinityList = new List<long>();
239

    
240
            int processCount = Environment.ProcessorCount;
241
            int AffinityScope = 1;
242

    
243
            if (processCount > MultiProcessCount)
244
            {
245
                AffinityScope = processCount / MultiProcessCount;
246
            }
247

    
248
            for (int i = 0; i < processCount - AffinityScope; i += AffinityScope)
249
            {
250
                var bits = new int[processCount];
251

    
252
                for (int j = i; j < i + AffinityScope; j++)
253
                {
254
                    bits[j] = 1;
255
                }
256

    
257
                var affinity = System.Convert.ToInt64(string.Join("", bits), 2);
258

    
259
                ProcessorAffinityList.Add(affinity);
260
            }
261
        }
262

    
263
        public bool StartService()
264
        {
265
          
266
            try
267
            {
268
                this.GetApplicationConfig();
269
                logger.Info("Read Config");
270

    
271
                ProcessorAffinityInit();
272

    
273
            }
274
            catch (Exception e)
275
            {
276
                throw new Exception("Stop StartService Error. ", e);
277
            }
278
            try
279
            {
280
                // MarkusPDF.dll에서 pThread lib 사용을 위해 Insatll
281
                if (!File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libpthread.dll")))
282
                {
283
                    Markus.Library.Installer.Install();
284
                    logger.Info("Markus.Library.Installer Install");
285
                }
286
                else
287
                {
288
                    logger.Info("Markus.Library.Installer Exists.");
289
                }
290
                
291
            }
292
            catch (Exception e)
293
            {
294
                throw new Exception("Stop Installer Error. ", e);
295
            }
296

    
297
            try
298
            {
299
                // 기존에 실행 중이던 프로세스 종료
300
                Stopprocess();
301
                logger.Info("Stopprocess");
302
            }
303
            catch (Exception e)
304
            {
305
                throw new Exception("Stop Process Error. ", e);
306
            }
307

    
308
            try
309
            {
310
                // WCF 실행
311
                StartWcfService();
312

    
313
                if (gWcfServiceHost.BaseAddresses?.Count() > 0)
314
                {
315
                    gServiceHostAddress = gWcfServiceHost.BaseAddresses.First();
316
                }
317

    
318
                //  각 서비스에 컨버터 아이템을 보내기 위한 서비스 초기화
319
                if (IsStation)
320
                {
321
                    SetServiceList(this.StationServiceIDList);
322
                }
323

    
324
                logger.Info($"StartWcfService {gServiceHostAddress}");
325
            }
326
            catch (Exception e)
327
            {
328
                throw new Exception("start Wcf Service Error. ", e);
329
            }
330

    
331
            //try
332
            //{
333
            //    // Status가 4이하인 Convert Item을 다시 Convert 함. 
334
            //    setDataBaseWaitingList();
335
            //    logger.Info("setDataBaseWaitingList");
336
            //}
337
            //catch (Exception e)
338
            //{
339
            //    throw new Exception("Database Waiting List Error . ", e);
340
            //}
341

    
342

    
343
            logger.Info("Start ServiceStation");
344
            
345
            timer = new System.Timers.Timer(new TimeSpan(0,0,0,10).TotalMilliseconds);
346
            timer.Elapsed += Timer_Elapsed;
347
            timer.AutoReset = true;
348
            timer.Start();
349

    
350
            return true;
351
        }
352

    
353
        public void SetServiceList(List<string> serviceList)
354
        {
355
            StationServiceList = new List<SubStationServiceItem>();
356

    
357
            using (DataBase.ConvertDatabase database = new DataBase.ConvertDatabase(MarkusDBConnectionString))
358
            {
359
                foreach (var item in serviceList)
360
                {
361
                    try
362
                    {
363
                        var prop = database.GetServiceProperties(item);
364

    
365
                        if (prop != null)
366
                        {
367
                            BasicHttpBinding myBinding = new BasicHttpBinding();
368
                            EndpointAddress myEndpoint = new EndpointAddress(UriHelper.UriCreate(prop.SERVICE_ADDRESS));
369
                            var StationServiceClient = new WcfClient.StationServiceTask.StationServiceClient(myBinding, myEndpoint);
370
                        
371
                       
372
                                //var items = StationServiceClient.AliveConvertList();
373
                            
374
                                StationServiceList.Add(new SubStationServiceItem
375
                                {
376
                                    Properties = prop,
377
                                    Service = StationServiceClient
378
                                });
379
                        }
380

    
381
                    }
382
                    catch (Exception ex)
383
                    {
384
                        logger.Error($"Service Properties Error  ID : { item }",ex);
385
                    }
386
                }
387
            }
388
        }
389

    
390
        protected override void OnStop()
391
        {
392
            try
393
            {
394
                timer.Stop();
395
                StopWcfService();
396
                Stopprocess();
397

    
398
                logger.Info("ServiceStation Stop");
399
            }
400
            catch (Exception e)
401
            {
402
                logger.Error("OnStop Error . ", e);
403
            }
404
        }
405

    
406
        #region Sleep 방지
407
        //[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
408
        //static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
409
        //[FlagsAttribute]
410
        //public enum EXECUTION_STATE : uint
411
        //{
412
        //    ES_AWAYMODE_REQUIRED = 0x00000040,
413
        //    ES_CONTINUOUS = 0x80000000,
414
        //    ES_DISPLAY_REQUIRED = 0x00000002,
415
        //    ES_SYSTEM_REQUIRED = 0x00000001
416
        //    // Legacy flag, should not be used.
417
        //    // ES_USER_PRESENT = 0x00000004
418
        //}
419
        //public static void PreventScreenAndSleep()
420
        //{
421
        //    SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS |
422
        //                            EXECUTION_STATE.ES_SYSTEM_REQUIRED |
423
        //                            EXECUTION_STATE.ES_AWAYMODE_REQUIRED |
424
        //                            EXECUTION_STATE.ES_DISPLAY_REQUIRED);
425
        //} 
426
        #endregion
427
    }
428
}
클립보드 이미지 추가 (최대 크기: 500 MB)