프로젝트

일반

사용자정보

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

markus / ConvertService / ServiceBase / Markus.Service.Station / ServiceStation.cs @ 1ae729e4

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

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

    
26
namespace Markus.Service
27
{
28
    public partial class ServiceStation : ServiceBase
29
    {
30
        protected ILog logger = LogManager.GetLogger(typeof(ServiceStation));
31
        protected ServiceHost gWcfServiceHost;
32
        private SERVICE_PROPERTIES ServiceProperty;
33

    
34
        private static System.Timers.Timer timer;
35
        
36
        private string ServiceID;
37
        private List<SubStationServiceItem> StationServiceList;
38
        private List<string> StationServiceIDList;
39
        private Service.WcfClient.StationServiceTask.StationServiceClient StationClient;
40
        private bool IsStation;
41

    
42
        private Uri gServiceHostAddress;
43

    
44
        private string MarkusDBConnectionString;
45
        private string DownloadTempFolder;
46
        private int MultiThreadMaxPages;
47
        private int MinFontSize;
48
        private int UseResolution;
49
        private bool CreateProcessWindow;
50
        private long ReleaseWorkMemory;
51

    
52
        private int SaveStatusInterval;
53

    
54
        private static bool IsReleaseItems;
55

    
56
        private List<string> RunProjectList = new List<string>();
57

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

    
63
        private string configFileName;
64

    
65
        public ServiceStation()
66
        {
67
            InitializeComponent();
68
        }
69

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

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

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

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

    
96
                    ServiceID = config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.SERVICE_ID, Guid.Empty.ToString());
97

    
98
                    if (IsStation)
99
                    {
100
                        var servicetList = config.GetValue(CONFIG_DEFINE.SERVICE, CONFIG_DEFINE.SERVICE_LIST, "");
101

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

    
111
                        if (!address.IsNullOrEmpty())
112
                        {
113
                            BasicHttpBinding myBinding = new BasicHttpBinding();
114
                            EndpointAddress myEndpoint = new EndpointAddress(UriHelper.UriCreate(address));
115
                            StationClient = new WcfClient.StationServiceTask.StationServiceClient(myBinding, myEndpoint);
116
                        }
117
                    }
118

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

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

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

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

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

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

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

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

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

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

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

    
148
                    if (!string.IsNullOrWhiteSpace(endpointName) && port.IsNumber())
149
                    {
150
                        gServiceHostAddress = UriHelper.UriCreate($"http://localhost:{port}/{endpointName}");
151
                    }
152

    
153
                    using (Markus.Service.DataBase.ConvertDatabase db = new Markus.Service.DataBase.ConvertDatabase(MarkusDBConnectionString))
154
                    {
155
                        ServiceProperty = db.GetServiceProperties(ServiceID);
156
                    }
157
                }
158
            }
159
            catch (Exception ex)
160
            {
161
                throw new Exception("ApplicationConfig ", ex);
162
            }
163
        }
164

    
165
        protected override void OnStart(string[] args)
166
        {
167
            try
168
            {
169
                StartService();
170
            }
171
            catch (Exception ex)
172
            {
173
                logger.Error("ServiceStation Start Error - ", ex);
174
            }
175
        }
176

    
177
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
178
        {
179
     
180
            //System.Diagnostics.Debug.WriteLine("timer : " + e?.SignalTime);
181
            //try
182
            //{
183
            //    if (!IsReleaseItems)
184
            //    {
185
            //        ReleaseItems();
186
            //    }
187

    
188
            //    if ((DateTime.Now - logTime) >= new TimeSpan(0, 5, 0))
189
            //    {
190
            //        logTime = DateTime.Now;
191
            //        logger.Info("StationService Alive Check");
192
            //    }
193
            //}
194
            //catch (Exception ex)
195
            //{
196
            //    logger.Error("Timer Error " ,ex);
197
            //}
198

    
199
            //System.Threading.Thread.SpinWait(1000);
200

    
201
            //timer.Start();
202
        }
203

    
204
        /// <summary>
205
        /// alivequeue와 process를 비교하여 정리하고
206
        /// 대기중인 아이템을 분배한다.
207
        /// </summary>
208
        private void ReleaseItems()
209
        {
210
            try
211
            {
212
                IsReleaseItems = true;
213

    
214
                CleanUpAliveQueueItems();
215

    
216
                if (IsStation)
217
                {
218
                    //if (IsDataBaseWaitingList(1))
219
                    //{
220
                    System.Diagnostics.Debug.WriteLine("ReleaseItems start");
221
                    ReflashSubServiceAsync();
222

    
223
                    if (StationServiceList.All(x => x.IsOnline))
224
                    {
225
                        CleanUpDataBaseItems();
226
                        setDataBaseWaitingList();
227
                    }
228
                    else
229
                    {
230
                        System.Diagnostics.Debug.WriteLine("Service Any Offline");
231
                    }
232

    
233
                    System.Diagnostics.Debug.WriteLine("ReleaseItems end");
234
                    //}
235
                }
236
            }
237
            catch (Exception ex)
238
            {
239
                logger.Error("get Wating Item error", ex);
240
            }
241

    
242
            IsReleaseItems = false;
243
        }
244

    
245
        /// <summary>
246
        /// System.Diagnostics.Process의 ProcessorAffinity Core 선호도를 위한 초기화
247
        /// 설정된 MultiProcessCount에 대해서 프로세스의 코어의 선호도를 지정 한다.
248
        /// 코어의 선택은 비트로 이루어 진다.
249
        /// 8코어에서 1번 코어 00000001
250
        /// 8코어에서 1번 3번 코어 00000101
251
        /// 8코어에서 1번 3번 코어 00000101
252
        /// 8코어에서 1,2,3 선택   00000111
253
        /// https://dotnetgalactics.wordpress.com/2009/10/20/how-to-set-the-processor-affinity-programatically/
254
        /// </summary>
255
        private void ProcessorAffinityInit()
256
        {
257
            ProcessorAffinityList = new List<long>();
258

    
259
            int processCount = Environment.ProcessorCount;
260
            int AffinityScope = 1;
261

    
262
            if (processCount > ServiceProperty.PROCESS_COUNT)
263
            {
264
                AffinityScope = processCount / ServiceProperty.PROCESS_COUNT;
265
            }
266

    
267
            for (int i = 0; i < processCount - AffinityScope; i += AffinityScope)
268
            {
269
                var bits = new int[processCount];
270

    
271
                for (int j = i; j < i + AffinityScope; j++)
272
                {
273
                    bits[j] = 1;
274
                }
275

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

    
278
                ProcessorAffinityList.Add(affinity);
279
            }
280
        }
281

    
282
        public bool StartService()
283
        {
284
          
285
            try
286
            {
287
                this.GetApplicationConfig();
288
                logger.Info("Read Config");
289

    
290
                if (ServiceProperty != null)
291
                {
292
                    ProcessorAffinityInit();
293
                }
294
                else
295
                {
296
                    throw new Exception("StartService Error. ServiceProperty is Null");
297
                }
298

    
299
            }
300
            catch (Exception e)
301
            {
302
                throw new Exception("StartService Error. ", e);
303
            }
304

    
305
            try
306
            {
307
                // MarkusPDF.dll에서 pThread lib 사용을 위해 Insatll
308
                if (!File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libpthread.dll")))
309
                {
310
                    Markus.Library.Installer.Install();
311
                    logger.Info("Markus.Library.Installer Install");
312
                }
313
                else
314
                {
315
                    logger.Info("Markus.Library.Installer Exists.");
316
                }
317
                
318
            }
319
            catch (Exception e)
320
            {
321
                throw new Exception("Stop Installer Error. ", e);
322
            }
323

    
324
            try
325
            {
326
                // 기존에 실행 중이던 프로세스 종료
327
                Stopprocess();
328
                logger.Info("Stopprocess");
329
            }
330
            catch (Exception e)
331
            {
332
                throw new Exception("Stop Process Error. ", e);
333
            }
334

    
335
            try
336
            {
337
                // WCF 실행
338
                StartWcfService();
339

    
340
                if (gWcfServiceHost.BaseAddresses?.Count() > 0)
341
                {
342
                    gServiceHostAddress = gWcfServiceHost.BaseAddresses.First();
343
                }
344

    
345
                //  각 서비스에 컨버터 아이템을 보내기 위한 서비스 초기화
346
                if (IsStation)
347
                {
348
                    SetServiceList(this.StationServiceIDList);
349
                }
350

    
351
                logger.Info($"StartWcfService {gServiceHostAddress}");
352
            }
353
            catch (Exception e)
354
            {
355
                throw new Exception("start Wcf Service Error. ", e);
356
            }
357

    
358
            //try
359
            //{
360
            //    // Status가 4이하인 Convert Item을 다시 Convert 함. 
361
            //    setDataBaseWaitingList();
362
            //    logger.Info("setDataBaseWaitingList");
363
            //}
364
            //catch (Exception e)
365
            //{
366
            //    throw new Exception("Database Waiting List Error . ", e);
367
            //}
368

    
369

    
370
            logger.Info("Start ServiceStation");
371
            var autoEvent = new System.Threading.AutoResetEvent(false);
372

    
373
            stateTimer = new System.Threading.Timer(new System.Threading.TimerCallback(TimerCallBack), null, 0, 500);
374
            //timer = new System.Timers.Timer(new TimeSpan(0, 0, 0, 10).TotalMilliseconds);
375
            //timer.Elapsed += Timer_Elapsed;
376
            //timer.AutoReset = true;
377
            //timer.Start();
378
            //Timer_Elapsed(null, null);
379
            return true;
380
        }
381

    
382
        System.Threading.Timer stateTimer;
383
        DateTime logTime;
384
        DateTime ReleaseTime;
385

    
386
        private void TimerCallBack(object state)
387
        {
388
            System.Threading.AutoResetEvent autoEvent = (System.Threading.AutoResetEvent)state;
389
            //stateTimer.Change(-1, -1);
390
            try
391
            {
392
               
393
                if ((DateTime.Now - ReleaseTime) >= new TimeSpan(0, 0,15))
394
                {
395
                    if (!IsReleaseItems)
396
                    {
397
                        ReleaseItems();
398
                    }
399
                    ReleaseTime = DateTime.Now;
400
                }
401
              
402

    
403
                if ((DateTime.Now - logTime) >= new TimeSpan(0, 5, 0))
404
                {
405
                    logTime = DateTime.Now;
406
                    logger.Info("StationService Alive Check");
407
                }
408

    
409

    
410
            }
411
            catch (Exception ex)
412
            {
413
                logger.Error("Timer Error ", ex);
414
            }
415

    
416
            ///System.Threading.Thread.SpinWait(100000);
417
            //stateTimer.Change(0, 10000);
418
        }
419

    
420
        public void SetServiceList(List<string> serviceList)
421
        {
422
            StationServiceList = new List<SubStationServiceItem>();
423

    
424
            using (DataBase.ConvertDatabase database = new DataBase.ConvertDatabase(MarkusDBConnectionString))
425
            {
426
                foreach (var item in serviceList)
427
                {
428
                    try
429
                    {
430
                        var prop = database.GetServiceProperties(item);
431

    
432
                        if (prop != null)
433
                        {
434
                            BasicHttpBinding httpbinding = new BasicHttpBinding();
435
                            httpbinding.CloseTimeout = new TimeSpan(0, 10, 0);
436
                            httpbinding.ReceiveTimeout = new TimeSpan(0, 10, 0);
437
                            httpbinding.SendTimeout = new TimeSpan(0, 10, 0);
438
                            httpbinding.OpenTimeout = new TimeSpan(0, 10, 0);
439

    
440
                            EndpointAddress myEndpoint = new EndpointAddress(UriHelper.UriCreate(prop.SERVICE_ADDRESS));
441
                            var StationServiceClient = new WcfClient.StationServiceTask.StationServiceClient(httpbinding, myEndpoint);
442
                        
443
                       
444
                                //var items = StationServiceClient.AliveConvertList();
445
                            
446
                                StationServiceList.Add(new SubStationServiceItem
447
                                {
448
                                    Properties = prop,
449
                                    Service = StationServiceClient
450
                                });
451
                        }
452

    
453
                    }
454
                    catch (Exception ex)
455
                    {
456
                        logger.Error($"Service Properties Error  ID : { item }",ex);
457
                    }
458
                }
459
            }
460
        }
461

    
462
        protected override void OnStop()
463
        {
464
            try
465
            {
466
                if (timer != null)
467
                {
468
                    timer.Stop();
469
                }
470

    
471
                StopWcfService();
472
                Stopprocess();
473

    
474
                logger.Info("ServiceStation Stop");
475
            }
476
            catch (Exception e)
477
            {
478
                logger.Error("OnStop Error . ", e);
479
            }
480
        }
481

    
482
        #region Sleep 방지
483
        //[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
484
        //static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
485
        //[FlagsAttribute]
486
        //public enum EXECUTION_STATE : uint
487
        //{
488
        //    ES_AWAYMODE_REQUIRED = 0x00000040,
489
        //    ES_CONTINUOUS = 0x80000000,
490
        //    ES_DISPLAY_REQUIRED = 0x00000002,
491
        //    ES_SYSTEM_REQUIRED = 0x00000001
492
        //    // Legacy flag, should not be used.
493
        //    // ES_USER_PRESENT = 0x00000004
494
        //}
495
        //public static void PreventScreenAndSleep()
496
        //{
497
        //    SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS |
498
        //                            EXECUTION_STATE.ES_SYSTEM_REQUIRED |
499
        //                            EXECUTION_STATE.ES_AWAYMODE_REQUIRED |
500
        //                            EXECUTION_STATE.ES_DISPLAY_REQUIRED);
501
        //} 
502
        #endregion
503
    }
504
}
클립보드 이미지 추가 (최대 크기: 500 MB)