프로젝트

일반

사용자정보

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

markus / ConvertService / ServiceBase / Markus.Service.Station / StationService / ServiceStationTask.cs @ a5e5fff6

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

1
using Markus.Message;
2
using System;
3
using System.Collections.Generic;
4
using System.Diagnostics;
5
using System.Linq;
6
using System.Text;
7
using System.Threading;
8
using System.Threading.Tasks;
9
using System.Management;
10
using static Markus.Service.Extensions.Encrypt;
11
using Markus.Service.Extensions;
12
using Markus.Service.Helper;
13
using Markus.Service.DataBase.Entities;
14
using Markus.Service.DataBase.Repositories;
15

    
16
namespace Markus.Service
17
{
18
    /// <summary>
19
    /// 컨버터 큐 처리 
20
    /// </summary>
21
    public partial class ServiceStation
22
    {
23
        /// <summary>
24
        /// 컨버터 실행중인 item
25
        /// </summary>
26
        private static List<ConvertDoc> AliveConvertQueue = new List<ConvertDoc>();
27

    
28
        /// <summary>
29
        /// 컨버터 프로세스 실행
30
        /// </summary>
31
        /// <param name="convertitem"></param>
32
        public bool ConvertProcessStart(ConvertDoc convertitem)
33
        {
34
            bool result = false;
35
            try
36
            {
37
           
38
                Process ConvertProcess = new Process();
39

    
40
                ProcessContext processSendData = new ProcessContext
41
                {
42
                    ConvertID = convertitem.ID,
43
                    ConnectionString = MarkusDBConnectionString,
44
                    ServiceStationUri = gServiceHostAddress.ToString(),
45
                    OriginFilePath = convertitem.DOCUMENT_URL,
46
                    SaveDirectory = convertitem.ConvertPath,
47
                    TempDirectory = DownloadTempFolder,
48
                    ReleaseWorkMemory = ReleaseWorkMemory,
49
                    MultiThreadMaxPages = MultiThreadMaxPages,
50
                    MinFontSize = MinFontSize,
51
                    SendStatusInterval = SaveStatusInterval,
52
                    UseResolution = UseResolution,
53
                    FontsFolder = FontsFolder
54
                };
55

    
56
                var sendData = ObjectToBytesStringConvert.ObjectToBytesString(processSendData);
57
                var convertPath = System.IO.Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Convert\\Markus.Service.ConvertProcess.exe");
58

    
59
                ProcessStartInfo startInfo = new ProcessStartInfo
60
                {
61
                    UseShellExecute = false,
62
                    FileName = convertPath,
63
                    WindowStyle = ProcessWindowStyle.Hidden,
64
                    CreateNoWindow = true,
65
                    ErrorDialog = false,
66
                    RedirectStandardError = false,
67
                    Arguments = $"{convertitem.ID.ToString()} {AESEncrypter.Encrypt(sendData)}"
68
                    //Arguments = $"{convertitem.ConvertID.ToString()} {convertitem.ProjectNumber} {AESEncrypter.Encrypt(MarkusDBConnectionString)} {gServiceHostAddress} {DownloadTempFolder} {MultiThreadMaxPages}"
69
                };
70

    
71
                ConvertProcess.StartInfo = startInfo;
72
                ConvertProcess.EnableRaisingEvents = true;
73
                
74
                System.Diagnostics.Debug.WriteLine("convert process run : " + startInfo.Arguments);
75

    
76
                logger.Info($"convert process run : ConvertDoc ID:{convertitem.ID}" + startInfo.Arguments);
77

    
78
                if (ConvertProcess.Start())
79
                {
80
                    try
81
                    {
82
                        var processAffinity = ProcessorAffinityList.Except(AliveConvertQueue.Select(f => (long)f.ProcessorAffinity));
83

    
84
                        long currentAffinity = 0;
85

    
86
                        if (processAffinity.Count() > 0)
87
                        {
88
                            currentAffinity = processAffinity.First();
89

    
90
                            //int bitMask = 1 << (convertitem.ProcessorAffinity - 1);
91
                            //bitMask |= 1 << (anotherUserSelection - 1); / //  프로세스 두개 이상 선택
92

    
93
                            ConvertProcess.ProcessorAffinity = new IntPtr(currentAffinity);
94
                            logger.Info($"convert process currentAffinity set {currentAffinity} : ConvertDoc ID:{convertitem.ID}");
95

    
96
                        }
97
                        else
98
                        {
99
                            // 모두 사용중일때 점유율이 작은 걸로 사용
100
                            var CurrentProcessAffinity = AliveConvertQueue.Where(x=>x.ProcessorAffinity > 0).Select(f => f.ProcessorAffinity).Distinct();
101

    
102
                            currentAffinity = CurrentProcessAffinity.Min();
103
                            ConvertProcess.ProcessorAffinity = new IntPtr(currentAffinity);
104

    
105
                            logger.Info($"convert process Affinity All use {currentAffinity} :  ConvertDoc ID:{convertitem.ID}");
106

    
107
                        }
108

    
109
                        var item = AliveConvertQueue.Find(x => x.Equals(convertitem));
110

    
111
                        if (item != null)
112
                        {
113
                            item.ProcessorAffinity = currentAffinity;
114
                        }
115
                    }
116
                    catch (Exception ex)
117
                    {
118
                        AliveConvertQueue.Remove(convertitem);
119
                        logger.Error("ConvertProcessStart error", ex);
120
                    }
121

    
122
                    logger.Info($"convert process run true ConvertDoc ID:{convertitem.ID}");
123
                    result = true;
124
                }
125
            }
126
            catch (Exception ex)
127
            {
128
                AliveConvertQueue.Remove(convertitem);
129
                throw new Exception("ConvertThread " + $" ConvertDoc ID:{convertitem.ID} {convertitem.PROJECT_NO} {AESEncrypter.Encrypt(MarkusDBConnectionString)} {gServiceHostAddress} {DownloadTempFolder} {MultiThreadMaxPages}", ex.InnerException);
130
            }
131
            finally
132
            {
133
                //GC.WaitForPendingFinalizers();
134
                //GC.Collect(2);
135
                //GC.Collect(2);
136
            }
137

    
138
            return result;
139
        }
140
    
141
        /// <summary>
142
        /// DB에 있는 대기중인 Item을 가져온다.
143
        /// </summary>
144
        public void setDataBaseWaitingList()
145
        {
146
            using (ConvertDocRepository database = new ConvertDocRepository(MarkusDBConnectionString))
147
            {
148
                int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
149

    
150
                var convertItems = database.GetWaitorErrorAsync(totalProcessCount).GetAwaiter().GetResult();
151

    
152
                foreach (var convert in convertItems)
153
                {
154
                    //ReflashSubService();
155

    
156
                    if (AliveConvertQueue.Count(x => x.ID == convert.ID || x.DOCUMENT_ID == convert.DOCUMENT_ID) == 0)
157
                    {
158
                        if (convert.STATUS > (int)StatusCodeType.None)
159
                        {
160
                            var result = database.SetCleanUpItemAsync(convert.ID, 1).GetAwaiter().GetResult();
161

    
162
                            if (result != 1)
163
                            {
164
                                throw new Exception($"SetCleanUpItem result :{result} {convert.ID}");
165
                            }
166
                        }
167

    
168
                        ConvertProcessAdd(convert.PROJECT_NO, convert.ID);
169
                        //PassConvertItem(convert.PROJECT_NO, convert.ID, convert.DOCUMENT_ID);
170

    
171
                        //System.Threading.Thread.Sleep(1000);
172
                    }
173
#if DEBUG
174
                    else
175
                    {
176
                        if (AliveConvertQueue.Count(x => x.ID == convert.ID) > 0)
177
                        {
178
                            if (System.Environment.UserInteractive)
179
                            {
180
                                Console.WriteLine($"AliveConvertQueue.Count(x => x.ID == convert.ID) : {convert.ID}");
181
                            }
182
                        }
183

    
184
                        if (AliveConvertQueue.Count(x=> x.DOCUMENT_ID == convert.DOCUMENT_ID) > 0)
185
                        {
186
                            if (System.Environment.UserInteractive)
187
                            {
188
                                Console.WriteLine($"AliveConvertQueue.Count(x.DOCUMENT_ID == convert.DOCUMENT_ID) : {convert.DOCUMENT_ID}");
189
                            }
190
                        }
191

    
192
                    }
193
#endif
194
                    /// 2022.11.28 수정
195
                    if (AliveConvertQueue.Count >= this.ServiceProperty.PROCESS_COUNT)
196
                    {
197
                        break;
198
                    }
199
                }
200
            }
201
        }
202

    
203
        /// <summary>
204
        /// DB에 있는 대기중인 Item을 가져온다.
205
        /// </summary>
206
        //public void setDataBaseWaitingLista()
207
        //{
208

    
209
        //    List<EntityModel.CONVERTER_DOC> convertItems = new List<EntityModel.CONVERTER_DOC>();
210

    
211
        //    using (DataBase.ConvertDatabase database = new DataBase.ConvertDatabase(MarkusDBConnectionString))
212
        //    {
213
        //        // 전체 서비스의 process count 만큼 waiting item을 가져온다.
214
        //        int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
215
        //        convertItems = database.GetWaitConvertItems(this.RunProjectList, totalProcessCount).ToList();
216
        //    }
217

    
218
        //    foreach (var convert in convertItems)
219
        //    {
220
        //        //ReflashSubService();
221

    
222
        //        if (AliveConvertQueue.Count(x => x.ConvertID == convert.ID) == 0)
223
        //        {
224
        //            if (convert.STATUS > (int)StatusCodeType.None)
225
        //            {
226
        //                using (DataBase.ConvertDatabase database = new DataBase.ConvertDatabase(MarkusDBConnectionString))
227
        //                {
228
        //                    database.SetCleanUpItem(convert.ID, 1);
229
        //                }
230
        //            }
231
        //            ConvertProcessAdd(convert.PROJECT_NO, convert.ID);
232
        //            //PassConvertItem(convert.PROJECT_NO, convert.ID, convert.DOCUMENT_ID);
233

    
234
        //            //System.Threading.Thread.Sleep(1000);
235
        //        }
236

    
237
        //        /// 2022.11.28 수정
238
        //        if (AliveConvertQueue.Count >= this.ServiceProperty.PROCESS_COUNT)
239
        //        {
240
        //            break;
241
        //        }
242
        //    }
243

    
244
        //}
245

    
246
        public bool IsDataBaseWaitingList(int overListCount)
247
        {
248
            bool result = false;
249

    
250
            try
251
            {
252
                using (ConvertDocRepository convertDatabase = new ConvertDocRepository(MarkusDBConnectionString))
253
                {
254
                    var convertItems = convertDatabase.GetWaitorErrorAsync(overListCount).GetAwaiter().GetResult();
255

    
256
                    if (convertItems.Count() > 0)
257
                    {
258
                        result = true;
259
                    }
260
                }
261
            }
262
            catch (Exception ex)
263
            {
264
                logger.Error($"IsDataBaseWaitingList Error",ex);
265
            }
266

    
267
            return result;
268
        }
269

    
270
        private async Task<bool> ReflashSubServiceAsync()
271
        {
272
            bool result = false;
273

    
274
            try
275
            {
276
                foreach (var subservice in StationServiceList)
277
                {
278
                    try
279
                    {
280
                        subservice.IsOnline = await SytemNet.PingAsync(subservice.Properties.SERVICE_ADDRESS);
281

    
282
                        if (subservice.IsOnline)
283
                        {
284
                            var alivelist = await subservice.Service.AliveConvertListAsync();
285

    
286
                            subservice.ConvertItems = alivelist.Cast<ConvertDoc>().ToList();
287
                            subservice.AliveCount = alivelist.Count();
288
                        }
289
                        else
290
                        {
291
                            logger.Error($"Connection Error {subservice.Properties.SERVICE_ADDRESS}");
292
                            subservice.ConvertItems = new List<ConvertDoc>();
293
                            subservice.AliveCount = subservice.Properties.PROCESS_COUNT;
294
                        }
295

    
296
                        result = true;
297
                    }
298
                    catch (Exception ex)
299
                    {
300
                        logger.Error($"ReflashSubService error - Service ID : {subservice.Properties.ID} ", ex);
301
                    }
302
                }
303
            }
304
            catch (Exception ex)
305
            {
306
                logger.Error($"ReflashSubService error", ex);
307
            }
308

    
309
            return result;
310
        }
311

    
312

    
313
        /// <summary>
314
        /// 
315
        /// </summary>
316
        /// <param name="ProjectNo"></param>
317
        /// <param name="ConvertID"></param>
318
        /// <param name="UniqueKey">Document ID(문서의 유일키)</param>
319
        private async void PassConvertItem(string ProjectNo,string ConvertDocID,bool isSubStation = false)
320
        {
321
            try
322
            {
323
                IEnumerable<SubStationServiceItem> stationList = null;
324

    
325
                //if (!isSubStation)
326
                //{
327
                    stationList = StationServiceList.Where(x => x.IsOnline);
328
                //}
329
                //else
330
                //{
331
                //    stationList = StationServiceList.Where(x => x.Properties.ID != this.ServiceID && x.IsOnline);
332
                //}
333

    
334
                if (stationList.SelectMany(x => x.ConvertItems).Count(c => c.PROJECT_NO == ProjectNo && c.ID == ConvertDocID) == 0)
335
                {
336
                    var station = stationList.OrderByDescending(x => x.Properties.PROCESS_COUNT - x.AliveCount).FirstOrDefault();
337

    
338
                    if (station != null)
339
                    {
340
                        if (station.Properties.PROCESS_COUNT - station.AliveCount > 0)
341
                        {
342
                            System.Diagnostics.Debug.WriteLine($"{station.Properties.SERVICE_ADDRESS}  {station.Properties.PROCESS_COUNT}/{station.AliveCount}");
343
                            var result = await station.Service.PassConvertAsync(ProjectNo, ConvertDocID);
344

    
345
                            if (!result.IsNullOrEmpty())
346
                            {
347
                                if (result.ToLower() == true.ToString().ToLower())
348
                                {
349
                                    Console.WriteLine($"PassConvertItem - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
350
                                    logger.Info($"PassConvertItem - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
351

    
352
                                    station.AliveCount++;
353
                                }
354
                                else
355
                                {
356
                                        logger.Error($"PassConvertItem Error result : {result} - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
357
                                }
358
                            }
359
                            else
360
                            {
361
                                logger.Error($"PassConvertItem result: Nulll; - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
362
                                System.Diagnostics.Debug.WriteLine("result : Nulll;");
363
                            }
364
                        }
365
                    }
366
                }
367
            }
368
            catch (Exception ex)
369
            {
370
                logger.Error($"setDataBaseWaitingList", ex);
371
            }
372
        }
373

    
374
        /// <summary>
375
        /// 컨버터 프로세스와 AiliveItems을 비교하여 AliveItems에 없는 경우 AliveItems을 제거
376
        /// </summary>
377
        private void CleanUpAliveQueueItems()
378
        {
379
            if (AliveConvertQueue.Count() > 0)
380
            {
381
                var processList = Process.GetProcessesByName("Markus.Service.ConvertProcess");
382

    
383
                if (processList.Length == 0)
384
                {
385
                    AliveConvertQueue.Clear();
386
                    System.Diagnostics.Debug.WriteLine("AliveConvertQueue.Clear()");
387
                }
388
                else
389
                {
390
                    var argumentList = processList.Where(x=> !x.HasExited).Select(f => f.Arguments().CommandLine).SelectMany(f => f).ToList();
391

    
392
                    List<ConvertDoc> convertItems = AliveConvertQueue;
393

    
394
                    try
395
                    {
396
                        if (convertItems.Count() > 0 && argumentList.Count() > 0)
397
                        {
398
                            for (int i = convertItems.Count - 1; i >= 0; --i)
399
                            {
400
                                if (argumentList.Count(x => x == convertItems[i].ID) == 0)
401
                                {
402
                                    System.Diagnostics.Debug.WriteLine($"AliveConvertQueue remove {convertItems[i].ID}");
403
                                    logger.Warn($"AliveConvertQueue remove {convertItems[i].ID}");
404
                                    AliveConvertQueue.Remove(convertItems[i]);
405

    
406
                                }
407
                            }
408
                        }
409
                    }
410
                    catch (Exception ex)
411
                    {
412
                        logger.Error("CleanUpAliveQueueItems error",ex);
413
                    }
414
                }
415
            }
416
        }
417

    
418
        /// <summary>
419
        /// AliveConvertQueue와 db를 비교하여 AliveConvertQueue에 없는 데이터를 초기화 하여 다시 컨버팅
420
        /// </summary>
421
        private async void CleanUpDataBaseItems()
422
        {
423
            try
424
            {
425
                int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
426

    
427
                using (DataBase.Repositories.ConvertDocRepository repository = new DataBase.Repositories.ConvertDocRepository(MarkusDBConnectionString))
428
                {
429
                    var items = repository.GetConvertingItemAsync(totalProcessCount).GetAwaiter().GetResult();
430

    
431
                    List<ConvertDoc> aliveItems = new List<ConvertDoc>();
432

    
433
                    aliveItems.AddRange(this.AliveConvertList());
434

    
435
                    foreach (var item in StationServiceList.Where(x => x.IsOnline))
436
                    {
437
                        var serviceItems = await item.Service.AliveConvertListAsync();
438
                        aliveItems.AddRange(serviceItems.Cast<ConvertDoc>());
439
                    }
440

    
441
                    if (aliveItems.Count() > 0)
442
                    {
443
                        logger.Warn($"aliveItems  : {string.Join(",",aliveItems.Select(x=>x.ID))}");
444

    
445
                        foreach (var item in items)
446
                        {
447
                            if (aliveItems.Count(x => x.ID == item.ID) == 0)
448
                            {
449
                                Console.WriteLine($"SetCleanUpItem  : {item.ID}");
450
                                logger.Warn($"SetCleanUpItem  : {item.ID}");
451
                                repository.SetCleanUpItemAsync(item.ID, 0).GetAwaiter().GetResult();
452
                            }
453
                        }
454
                    }
455
             
456
                }
457
            }
458
            catch (Exception ex)
459
            {
460
                throw new Exception("CleanUpDataBaseItems Error ", ex);
461
            }
462
        }
463

    
464
        public void Stopprocess()
465
        {
466
            var process = Process.GetProcessesByName("Markus.Service.ConvertProcess");
467

    
468
            for (int i = process.Count() - 1; i >= 0 ; i--)
469
            {
470
                try
471
                {
472
                    Console.WriteLine($"{i} Process Kill");
473
                    process[i].Kill();
474
                }
475
                catch (Exception ex)
476
                {
477
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
478
                }
479
            }
480
        }
481

    
482
        /// <summary>
483
        /// finish가 호출되고 살아있는 프로세스라고 추정됨
484
        /// </summary>
485
        public void DeadLockProcessKill()
486
        {
487
            var process = Process.GetProcessesByName("Markus.Service.ConvertProcess");
488

    
489
            for (int i = process.Count() - 1; i >= 0; i--)
490
            {
491
                try
492
                {
493
                    var commandLines = process[i].Arguments().CommandLine;
494

    
495
                    if (commandLines.Count() > 0)
496
                    {
497
                        if (ServiceStation.AliveConvertQueue.Count(f => f.ID == commandLines[0]) == 0)
498
                        {
499
                            process[i].Kill();
500
                        }
501
                    }
502
                }
503
                catch (Exception ex)
504
                {
505
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
506
                }
507
            }
508
        }
509

    
510
        private async void ConvertFinish(ConvertDoc convertitem)
511
        {
512
            try
513
            {
514
                System.Diagnostics.Debug.WriteLine("Convert Finish : " + convertitem.ID);
515

    
516
                System.Diagnostics.Debug.WriteLine("ServiceStation.AliveConvertQueue.Count() : " + ServiceStation.AliveConvertQueue.Count());
517

    
518
                List<string> deleteItems = new List<string> { convertitem.ID };
519

    
520

    
521
                ServiceStation.AliveConvertQueue.RemoveAll(x=>deleteItems.Any(y=>y == x.ID));
522

    
523
                System.Diagnostics.Debug.WriteLine("ServiceStation.AliveConvertQueue.Count() : " + ServiceStation.AliveConvertQueue.Count());
524

    
525
                if (IsStation)
526
                {
527
                    if (!IsReleaseItems)
528
                    {
529
                        System.Diagnostics.Debug.WriteLine("ConvertFinish ReleaseItems call");
530
                        ReleaseItems();
531
                    }
532
                }
533
                else
534
                {
535
                    if (StationClient != null)
536
                    {
537
                       await  StationClient.ReleaseConvertItemsAsync();
538
                    }
539
                }
540
                //if (ServiceStation.AliveConvertQueue.Count() < MultiProcessCount)
541
                //{
542
                //    setDataBaseWaitingList();
543
                //}
544
            }
545
            catch (Exception ex)
546
            {
547
                logger.Error("ConvertFinish Error",ex);
548
            }
549
        }
550
    }
551
}
클립보드 이미지 추가 (최대 크기: 500 MB)