프로젝트

일반

사용자정보

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

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

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

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

    
55
                var sendData = ObjectToBytesStringConvert.ObjectToBytesString(processSendData);
56
                var convertPath = System.IO.Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Convert");
57

    
58
                ProcessStartInfo startInfo = new ProcessStartInfo
59
                {
60
                    UseShellExecute = false,
61
                    FileName = System.IO.Path.Combine(convertPath, "Markus.Service.ConvertProcess.exe"),
62
                    WindowStyle = ProcessWindowStyle.Hidden,
63
                    CreateNoWindow = true,
64
                    ErrorDialog = false,
65
                    RedirectStandardError = false,
66
                    WorkingDirectory = convertPath,
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
                            ConvertProcess.ProcessorAffinity = new IntPtr(DefaultAffinity);
100

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

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

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

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

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

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

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

    
152
                    if (AliveConvertQueue.Count(x => x.ID == convert.ID 
153
                                              || x.DOCUMENT_ID == convert.DOCUMENT_ID  // 같은 경로로 다운로드 및 작업되어 추가
154
                                              || (x.STATUS <= (int)StatusCodeType.Wait && x.DOCUMENT_URL == convert.DOCUMENT_URL)) == 0)
155
                                                 //  같은 url을 다운로드시 서버의 퍼포먼스가 좋지 않으면 다운로드 오류 발생하여 추가
156
                    {
157
                        if (convert.STATUS > (int)StatusCodeType.None)
158
                        {
159
                            var result = database.SetCleanUpItemAsync(convert.ID, 1).GetAwaiter().GetResult();
160

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

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

    
170
                        //System.Threading.Thread.Sleep(1000);
171
                    }
172
#if DEBUG
173
                    else
174
                    {
175
                        if (AliveConvertQueue.Where(x => x.STATUS <= (int)StatusCodeType.Wait && x.DOCUMENT_URL == convert.DOCUMENT_URL) is var items)
176
                        {
177
                            if (System.Environment.UserInteractive)
178
                            {
179
                                if (items.Count() > 0)
180
                                {
181
                                    Console.WriteLine($"Same DOCUMENT_URL : {((StatusCodeType)items.First().STATUS).ToString()} - {items.First().DOCUMENT_URL}");
182
                                }
183
                            }
184
                        }
185

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

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

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

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

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

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

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

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

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

    
253
        //}
254

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

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

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

    
276
            return result;
277
        }
278

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

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

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

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

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

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

    
331
            return result;
332
        }
333

    
334

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

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

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

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

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

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

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

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

    
414
                    List<ConvertDoc> convertItems = AliveConvertQueue;
415

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

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

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

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

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

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

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

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

    
465

    
466
                        aliveItems.AddRange(convertDocItems);
467
                    }
468

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

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

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

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

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

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

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

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

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

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

    
548

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

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

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