프로젝트

일반

사용자정보

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

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

이력 | 보기 | 이력해설 | 다운로드 (23.9 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
                Process ConvertProcess = new Process();
38

    
39
                ProcessContext processSendData = new ProcessContext
40
                {
41
                    ConvertID = convertitem.ID,
42
                    ConnectionString = MarkusDBConnectionString,
43
                    DbmsType = DBMSType.ToString(),
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");
58

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

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

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

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

    
85
                        long currentAffinity = 0;
86

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

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

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

    
97
                        }
98
                        else
99
                        {
100
                            ConvertProcess.ProcessorAffinity = new IntPtr(DefaultAffinity);
101

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

    
105
                        var item = AliveConvertQueue.Find(x => x.Equals(convertitem));
106

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

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

    
134
            return result;
135
        }
136
    
137
        /// <summary>
138
        /// DB에 있는 대기중인 Item을 가져와서 프로세스 실행
139
        /// 
140
        /// </summary>
141
        public void setDataBaseWaitingList()
142
        {
143
            using (ConvertDocRepository database = new ConvertDocRepository(MarkusDBConnectionString,DBMSType))
144
            {
145
                int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
146

    
147
                var convertItems = database.GetWaitorErrorAsync(totalProcessCount).GetAwaiter().GetResult();
148

    
149
                foreach (var convert in convertItems)
150
                {
151
                    //ReflashSubService();
152

    
153
                    if (AliveConvertQueue.Count(x => x.ID == convert.ID 
154
                                              || x.DOCUMENT_ID == convert.DOCUMENT_ID  // 같은 경로로 다운로드 및 작업되어 추가
155
                                              || (x.STATUS <= (int)StatusCodeType.Wait && x.DOCUMENT_URL == convert.DOCUMENT_URL)) == 0)
156
                                                 //  같은 url을 다운로드시 서버의 퍼포먼스가 좋지 않으면 다운로드 오류 발생하여 추가
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.Where(x => x.STATUS <= (int)StatusCodeType.Wait && x.DOCUMENT_URL == convert.DOCUMENT_URL) is var items)
177
                        {
178
                            if (System.Environment.UserInteractive)
179
                            {
180
                                if (items.Count() > 0)
181
                                {
182
                                    Console.WriteLine($"Same DOCUMENT_URL : {((StatusCodeType)items.First().STATUS).ToString()} - {items.First().DOCUMENT_URL}");
183
                                }
184
                            }
185
                        }
186

    
187
                        if (AliveConvertQueue.Count(x => x.ID == convert.ID) > 0)
188
                        {
189
                            if (System.Environment.UserInteractive)
190
                            {
191
                                Console.WriteLine($"same convert.ID : {convert.ID}");
192
                            }
193
                        }
194

    
195
                        if (AliveConvertQueue.Count(x=> x.DOCUMENT_ID == convert.DOCUMENT_ID) > 0)
196
                        {
197
                            if (System.Environment.UserInteractive)
198
                            {
199
                                Console.WriteLine($"same convert.DOCUMENT_ID : {convert.DOCUMENT_ID}");
200
                            }
201
                        }
202
                    }
203
#endif
204
                    /// 2022.11.28 수정
205
                    if (AliveConvertQueue.Count >= this.ServiceProperty.PROCESS_COUNT)
206
                    {
207
                        break;
208
                    }
209
                }
210
            }
211
        }
212

    
213
        /// <summary>
214
        /// DB에 있는 대기중인 Item을 가져온다.
215
        /// </summary>
216
        //public void setDataBaseWaitingLista()
217
        //{
218

    
219
        //    List<EntityModel.CONVERTER_DOC> convertItems = new List<EntityModel.CONVERTER_DOC>();
220

    
221
        //    using (DataBase.ConvertDatabase database = new DataBase.ConvertDatabase(MarkusDBConnectionString,DBMSType))
222
        //    {
223
        //        // 전체 서비스의 process count 만큼 waiting item을 가져온다.
224
        //        int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
225
        //        convertItems = database.GetWaitConvertItems(this.RunProjectList, totalProcessCount).ToList();
226
        //    }
227

    
228
        //    foreach (var convert in convertItems)
229
        //    {
230
        //        //ReflashSubService();
231

    
232
        //        if (AliveConvertQueue.Count(x => x.ConvertID == convert.ID) == 0)
233
        //        {
234
        //            if (convert.STATUS > (int)StatusCodeType.None)
235
        //            {
236
        //                using (DataBase.ConvertDatabase database = new DataBase.ConvertDatabase(MarkusDBConnectionString,DBMSType))
237
        //                {
238
        //                    database.SetCleanUpItem(convert.ID, 1);
239
        //                }
240
        //            }
241
        //            ConvertProcessAdd(convert.PROJECT_NO, convert.ID);
242
        //            //PassConvertItem(convert.PROJECT_NO, convert.ID, convert.DOCUMENT_ID);
243

    
244
        //            //System.Threading.Thread.Sleep(1000);
245
        //        }
246

    
247
        //        /// 2022.11.28 수정
248
        //        if (AliveConvertQueue.Count >= this.ServiceProperty.PROCESS_COUNT)
249
        //        {
250
        //            break;
251
        //        }
252
        //    }
253

    
254
        //}
255

    
256
        public bool IsDataBaseWaitingList(int overListCount)
257
        {
258
            bool result = false;
259

    
260
            try
261
            {
262
                using (ConvertDocRepository convertDatabase = new ConvertDocRepository(MarkusDBConnectionString,DBMSType))
263
                {
264
                    var convertItems = convertDatabase.GetWaitorErrorAsync(overListCount).GetAwaiter().GetResult();
265

    
266
                    if (convertItems.Count() > 0)
267
                    {
268
                        result = true;
269
                    }
270
                }
271
            }
272
            catch (Exception ex)
273
            {
274
                logger.Error($"IsDataBaseWaitingList Error",ex);
275
            }
276

    
277
            return result;
278
        }
279

    
280
        private async Task<bool> ReflashSubServiceAsync()
281
        {
282
            bool result = false;
283

    
284
            try
285
            {
286
                foreach (var subservice in StationServiceList)
287
                {
288
                    try
289
                    {
290
                        if (subservice.Properties.ID == this.ServiceProperty.ID)
291
                        {
292
                            subservice.ConvertItems = this.AliveConvertList();
293
                            subservice.AliveCount = this.AliveConvertList().Count();
294
                        }
295
                        else
296
                        {
297
                            subservice.IsOnline = await SytemNet.PingAsync(subservice.Properties.SERVICE_ADDRESS);
298

    
299
                            if (subservice.IsOnline)
300
                            {
301
                                var alivelist = await subservice.Service.AliveConvertListAsync();
302

    
303
                                subservice.ConvertItems = alivelist.Select(x => 
304
                                                        new ConvertDoc(x.ID, x.PROJECT_NO, x.DOCUMENT_URL, x.DOCUMENT_ID, 
305
                                                        x.CREATE_DATETIME, x.STATUS, x.TOTAL_PAGE, x.CURRENT_PAGE,
306
                                                        x.RECONVERTER, x.EXCEPTION, x.END_DATETIME, x.START_DATETIME, x.SERVICE_ID)
307
                                                        ).ToList();
308

    
309
                                subservice.AliveCount = alivelist.Count();
310
                            }
311
                            else
312
                            {
313
                                logger.Error($"Connection Error {subservice.Properties.SERVICE_ADDRESS}");
314
                                subservice.ConvertItems = new List<ConvertDoc>();
315
                                subservice.AliveCount = subservice.Properties.PROCESS_COUNT;
316
                            }
317
                        }
318

    
319
                        result = true;
320
                    }
321
                    catch (Exception ex)
322
                    {
323
                        logger.Error($"ReflashSubService error - Service ID : {subservice.Properties.ID} ", ex);
324
                    }
325
                }
326
            }
327
            catch (Exception ex)
328
            {
329
                logger.Error($"ReflashSubService error", ex);
330
            }
331

    
332
            return result;
333
        }
334

    
335

    
336
        /// <summary>
337
        /// 
338
        /// </summary>
339
        /// <param name="ProjectNo"></param>
340
        /// <param name="ConvertID"></param>
341
        /// <param name="UniqueKey">Document ID(문서의 유일키)</param>
342
        private async void PassConvertItem(string ProjectNo,string ConvertDocID,bool isSubStation = false)
343
        {
344
            try
345
            {
346
                IEnumerable<SubStationServiceItem> stationList = null;
347

    
348
                //if (!isSubStation)
349
                //{
350
                    stationList = StationServiceList.Where(x => x.IsOnline);
351
                //}
352
                //else
353
                //{
354
                //    stationList = StationServiceList.Where(x => x.Properties.ID != this.ServiceID && x.IsOnline);
355
                //}
356

    
357
                if (stationList.SelectMany(x => x.ConvertItems).Count(c => c.PROJECT_NO == ProjectNo && c.ID == ConvertDocID) == 0)
358
                {
359
                    var station = stationList.OrderByDescending(x => x.Properties.PROCESS_COUNT - x.AliveCount).FirstOrDefault();
360

    
361
                    if (station != null)
362
                    {
363
                        if (station.Properties.PROCESS_COUNT - station.AliveCount > 0)
364
                        {
365
                            System.Diagnostics.Debug.WriteLine($"{station.Properties.SERVICE_ADDRESS}  {station.Properties.PROCESS_COUNT}/{station.AliveCount}");
366
                            var result = await station.Service.PassConvertAsync(ProjectNo, ConvertDocID);
367

    
368
                            if (!result.IsNullOrEmpty())
369
                            {
370
                                if (result.ToLower() == true.ToString().ToLower())
371
                                {
372
                                    Console.WriteLine($"PassConvertItem - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
373
                                    logger.Info($"PassConvertItem - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
374

    
375
                                    station.AliveCount++;
376
                                }
377
                                else
378
                                {
379
                                        logger.Error($"PassConvertItem Error result : {result} - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
380
                                }
381
                            }
382
                            else
383
                            {
384
                                logger.Error($"PassConvertItem result: Nulll; - Service ID : {station.Properties.ID} ConvertDocID : {ConvertDocID}");
385
                                System.Diagnostics.Debug.WriteLine("result : Nulll;");
386
                            }
387
                        }
388
                    }
389
                }
390
            }
391
            catch (Exception ex)
392
            {
393
                logger.Error($"PassConvertItem", ex);
394
            }
395
        }
396

    
397
        /// <summary>
398
        /// 컨버터 프로세스와 AiliveItems을 비교하여 AliveItems에 없는 경우 AliveItems을 제거
399
        /// </summary>
400
        private void CleanUpAliveQueueItems()
401
        {
402
            if (AliveConvertQueue.Count() > 0)
403
            {
404
                var processList = Process.GetProcessesByName("Markus.Service.ConvertProcess");
405

    
406
                if (processList.Length == 0)
407
                {
408
                    AliveConvertQueue.Clear();
409
                    System.Diagnostics.Debug.WriteLine("AliveConvertQueue.Clear()");
410
                }
411
                else
412
                {
413
                    var argumentList = processList.Where(x=> !x.HasExited).Select(f => f.Arguments().CommandLine).SelectMany(f => f).ToList();
414

    
415
                    List<ConvertDoc> convertItems = AliveConvertQueue;
416

    
417
                    try
418
                    {
419
                        if (convertItems.Count() > 0 && argumentList.Count() > 0)
420
                        {
421
                            for (int i = convertItems.Count - 1; i >= 0; --i)
422
                            {
423
                                if (argumentList.Count(x => x == convertItems[i].ID) == 0)
424
                                {
425
                                    System.Diagnostics.Debug.WriteLine($"AliveConvertQueue remove {convertItems[i].ID}");
426
                                    logger.Warn($"AliveConvertQueue remove {convertItems[i].ID}");
427
                                    AliveConvertQueue.Remove(convertItems[i]);
428

    
429
                                }
430
                            }
431
                        }
432
                    }
433
                    catch (Exception ex)
434
                    {
435
                        logger.Error("CleanUpAliveQueueItems error",ex);
436
                    }
437
                }
438
            }
439
        }
440

    
441
        /// <summary>
442
        /// AliveConvertQueue와 db를 비교하여 AliveConvertQueue에 없는 데이터를 초기화 하여 다시 컨버팅
443
        /// </summary>
444
        private async void CleanUpDataBaseItems()
445
        {
446
            try
447
            {
448
                int totalProcessCount = this.ServiceProperty.PROCESS_COUNT + StationServiceList.Where(x => x.IsOnline).Sum(f => f.Properties.PROCESS_COUNT);
449

    
450
                using (DataBase.Repositories.ConvertDocRepository repository = new DataBase.Repositories.ConvertDocRepository(MarkusDBConnectionString,DBMSType))
451
                {
452
                    var items = repository.GetConvertingItemAsync(totalProcessCount).GetAwaiter().GetResult();
453

    
454
                    List<ConvertDoc> aliveItems = new List<ConvertDoc>();
455

    
456
                    aliveItems.AddRange(this.AliveConvertList());
457

    
458
                    foreach (var item in StationServiceList.Where(x => x.IsOnline))
459
                    {
460
                        var serviceItems = await item.Service.AliveConvertListAsync();
461

    
462
                        var convertDocItems = serviceItems.Select(x => new ConvertDoc(x.ID, x.PROJECT_NO, x.DOCUMENT_URL, x.DOCUMENT_ID,
463
                                                        x.CREATE_DATETIME, x.STATUS, x.TOTAL_PAGE, x.CURRENT_PAGE,
464
                                                        x.RECONVERTER, x.EXCEPTION, x.END_DATETIME, x.START_DATETIME, x.SERVICE_ID));
465

    
466

    
467
                        aliveItems.AddRange(convertDocItems);
468
                    }
469

    
470
                    //if (aliveItems.Count() > 0)
471
                    //{
472
                    //logger.Warn($"aliveItems  : {string.Join(",",aliveItems.Select(x=>x.ID))}");
473

    
474
                        foreach (var item in items)
475
                        {
476
                            if (aliveItems.Count(x => x.ID == item.ID) == 0)
477
                            {
478
                                Console.WriteLine($"SetCleanUpItem  : {item.ID}");
479
                                logger.Warn($"SetCleanUpItem  : {item.ID}");
480
                                repository.SetCleanUpItemAsync(item.ID, 0).GetAwaiter().GetResult();
481
                            }
482
                        }
483
                    //}
484
             
485
                }
486
            }
487
            catch (Exception ex)
488
            {
489
                throw new Exception("CleanUpDataBaseItems Error ", ex);
490
            }
491
        }
492

    
493
        public void Stopprocess()
494
        {
495
            var process = Process.GetProcessesByName("Markus.Service.ConvertProcess");
496

    
497
            for (int i = process.Count() - 1; i >= 0 ; i--)
498
            {
499
                try
500
                {
501
                    Console.WriteLine($"{i} Process Kill");
502
                    process[i].Kill();
503
                }
504
                catch (Exception ex)
505
                {
506
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
507
                }
508
            }
509
        }
510

    
511
        /// <summary>
512
        /// finish가 호출되고 살아있는 프로세스라고 추정됨
513
        /// </summary>
514
        public void DeadLockProcessKill()
515
        {
516
            var process = Process.GetProcessesByName("Markus.Service.ConvertProcess");
517

    
518
            for (int i = process.Count() - 1; i >= 0; i--)
519
            {
520
                try
521
                {
522
                    var commandLines = process[i].Arguments().CommandLine;
523

    
524
                    if (commandLines.Count() > 0)
525
                    {
526
                        if (ServiceStation.AliveConvertQueue.Count(f => f.ID == commandLines[0]) == 0)
527
                        {
528
                            process[i].Kill();
529
                        }
530
                    }
531
                }
532
                catch (Exception ex)
533
                {
534
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
535
                }
536
            }
537
        }
538

    
539
        private async void ConvertFinish(ConvertDoc convertitem)
540
        {
541
            try
542
            {
543
                System.Diagnostics.Debug.WriteLine("Convert Finish : " + convertitem.ID);
544

    
545
                System.Diagnostics.Debug.WriteLine("ServiceStation.AliveConvertQueue.Count() : " + ServiceStation.AliveConvertQueue.Count());
546

    
547
                List<string> deleteItems = new List<string> { convertitem.ID };
548

    
549

    
550
                ServiceStation.AliveConvertQueue.RemoveAll(x=>deleteItems.Any(y=>y == x.ID));
551

    
552
                System.Diagnostics.Debug.WriteLine("ServiceStation.AliveConvertQueue.Count() : " + ServiceStation.AliveConvertQueue.Count());
553

    
554
                if (IsStation)
555
                {
556
                    if (!IsReleaseItems)
557
                    {
558
                        System.Diagnostics.Debug.WriteLine("ConvertFinish ReleaseItems call");
559
                        ReleaseItems();
560
                    }
561
                }
562
                //else
563
                //{
564
                //    if (StationClient != null)
565
                //    {
566
                //       await  StationClient.ReleaseConvertItemsAsync();
567
                //    }
568
                //}
569
                //if (ServiceStation.AliveConvertQueue.Count() < MultiProcessCount)
570
                //{
571
                //    setDataBaseWaitingList();
572
                //}
573
            }
574
            catch (Exception ex)
575
            {
576
                logger.Error("ConvertFinish Error",ex);
577
            }
578
        }
579
    }
580
}
클립보드 이미지 추가 (최대 크기: 500 MB)