পুনরায় চেষ্টা যুক্তি লেখার সবচেয়ে সহজ উপায়?


455

মাঝেমধ্যে হাল ছেড়ে দেওয়ার আগে বেশ কয়েকবার আমার আবার অপারেশন করার চেষ্টা করা দরকার। আমার কোডটি এর মতো:

int retries = 3;
while(true) {
  try {
    DoSomething();
    break; // success!
  } catch {
    if(--retries == 0) throw;
    else Thread.Sleep(1000);
  }
}

আমি এটিকে আবার সাধারণভাবে পুনরায় চেষ্টা করতে চাই যেমন:

TryThreeTimes(DoSomething);

এটি কি সি # তে সম্ভব? TryThreeTimes()পদ্ধতির কোড কী হবে ?


1
একটি সাধারণ চক্র যথেষ্ট নয়? কেন কেবল বারবার পুনরুক্তি করা এবং বেশ কয়েকবার যুক্তি সম্পাদন করা উচিত নয়?
রেস্টুটা

13
ব্যক্তিগতভাবে, আমি এই জাতীয় কোনও সহায়তা পদ্ধতি সম্পর্কে অত্যন্ত সতর্ক থাকব। ল্যাম্বডাস ব্যবহার করে এটি বাস্তবায়ন করা অবশ্যই সম্ভব, তবে প্যাটার্নটি নিজেই অত্যন্ত গন্ধযুক্ত, সুতরাং এটির জন্য একজন সহায়ককে পরিচয় করানো (যা বোঝায় যে এটি প্রায়শই পুনরাবৃত্তি করা হয়) এবং এটি অত্যন্ত সন্দেহজনক এবং খারাপ সামগ্রিক নকশার জন্য দৃ strongly়ভাবে ইঙ্গিত দেয়।
পাভেল মিনায়েভ

12
আমার ক্ষেত্রে, আমার ডসোমথিং (গুলি) ফাইলগুলি মুছে ফেলা, বা কোনও নেটওয়ার্ক পোর্টে আঘাত করার চেষ্টা করার মতো দূরবর্তী মেশিনে স্টাফ করছে। উভয় ক্ষেত্রেই, ডসোমিংথিং কখন সাফল্য পাবে এবং দূরবর্তীতার কারণে, আমি শুনতে পেলাম এমন কোনও ইভেন্ট নেই এর জন্য বড় সময়সীমার সমস্যা রয়েছে। হ্যাঁ, এটি গন্ধযুক্ত। পরামর্শ স্বাগত জানাই।
noctonura

13
@ পাভেলিমিনাভ খারাপ সামগ্রিক নকশায় পুনরায় চেষ্টা করার ইঙ্গিতটি ব্যবহার করবেন কেন? আপনি যদি অনেকগুলি কোড লিখেন যা ইন্টিগ্রেশন পয়েন্টগুলিকে সংযুক্ত করে তবে পুনরায় চেষ্টা করা অবশ্যই একটি প্যাটার্ন যা আপনার গুরুত্ব সহকারে ব্যবহার করা উচিত।
বাইটেডেভ

উত্তর:


569

কম্বল ধরার স্টেটমেন্টগুলি যা সাধারণ ব্যতিক্রম পরিচালনার ব্যবস্থা হিসাবে ব্যবহৃত হলে কেবল একই কলটির পুনরায় চেষ্টা করা বিপজ্জনক হতে পারে। এটি বলার পরে, এখানে একটি ল্যাম্বডা ভিত্তিক পুনরায় চেষ্টা করুন যা আপনি যে কোনও পদ্ধতিতে ব্যবহার করতে পারবেন wra আমি পুনরায় চেষ্টা করার সংখ্যা এবং কিছুটা আরও নমনীয়তার জন্য প্যারামিটার হিসাবে পুনরায় চেষ্টাের সময়সীমাকে বেছে নিয়েছি:

public static class Retry
{
    public static void Do(
        Action action,
        TimeSpan retryInterval,
        int maxAttemptCount = 3)
    {
        Do<object>(() =>
        {
            action();
            return null;
        }, retryInterval, maxAttemptCount);
    }

    public static T Do<T>(
        Func<T> action,
        TimeSpan retryInterval,
        int maxAttemptCount = 3)
    {
        var exceptions = new List<Exception>();

        for (int attempted = 0; attempted < maxAttemptCount; attempted++)
        {
            try
            {
                if (attempted > 0)
                {
                    Thread.Sleep(retryInterval);
                }
                return action();
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }
        }
        throw new AggregateException(exceptions);
    }
}

পুনরায় চেষ্টা করার জন্য আপনি এখন এই ইউটিলিটি পদ্ধতিটি ব্যবহার করতে পারেন:

Retry.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1));

বা:

Retry.Do(SomeFunctionThatCanFail, TimeSpan.FromSeconds(1));

বা:

int result = Retry.Do(SomeFunctionWhichReturnsInt, TimeSpan.FromSeconds(1), 4);

অথবা আপনি একটি asyncওভারলোডও করতে পারেন ।


7
+1, বিশেষত সতর্কতা এবং ত্রুটি-পরীক্ষার জন্য। যদিও জেনেরিক প্যারামিটার (যেখানে টি: ব্যতিক্রম) হিসাবে ধরা ব্যতিক্রমের ধরণের ক্ষেত্রে এটি পাস হলে আমি আরও স্বাচ্ছন্দ্যবোধ করব।
ট্রুউইল

1
এটি আমার উদ্দেশ্য ছিল যে "পুনরায় চেষ্টা" বলতে আসলে পুনরায় চেষ্টা করা হয়েছিল। তবে এটি "চেষ্টা করে" বোঝার জন্য এটি পরিবর্তন করা খুব বেশি কঠিন নয়। যতক্ষণ নামটি অর্থবহ রাখা হয়। কোড উন্নত করার জন্য অন্যান্য সুযোগ রয়েছে যেমন নেতিবাচক পুনরায় চেষ্টা করা বা নেতিবাচক সময়সীমা - যেমন for উদাহরণগুলি সহজ রাখার জন্য আমি এগুলি বাদ দিয়েছি ... তবে আবার বাস্তবে বাস্তবায়নের ক্ষেত্রে এটি সম্ভবত ভাল বৃদ্ধি হতে পারে।
এলবুষকিন

40
আমরা আমাদের ডিবি অ্যাক্সেসের জন্য একটি উচ্চ ভলিউম বিজটালক অ্যাপে একই ধরণের ব্যবহার করি তবে দুটি উন্নতি সহ: আমাদের ব্যতিক্রমগুলির জন্য কালো তালিকা রয়েছে যা পুনরায় চেষ্টা করা উচিত নয় এবং আমরা ঘটে যাওয়া প্রথম ব্যতিক্রমগুলি সংরক্ষণ করি এবং যখন চূড়ান্ত চেষ্টা ব্যর্থ হয় তখন ফেলে দেই throw দ্বিতীয় এবং নিম্নলিখিত ব্যতিক্রমগুলি প্রায়শই প্রথমের থেকে পৃথক Re সেক্ষেত্রে আপনি কেবলমাত্র সর্বশেষ ব্যতিক্রমটি পুনর্বিবেচনা করার সময় প্রাথমিক সমস্যাটি লুকান।
টিটোনি

2
@ ডেক্সটার্স আমরা মূল ব্যতিক্রমটিকে অভ্যন্তরীণ ব্যতিক্রম হিসাবে নিক্ষেপ করি। মূল স্ট্যাক ট্রেস অভ্যন্তরীণ ব্যতিক্রমগুলি থেকে অ্যাট্রিবিউট হিসাবে উপলব্ধ।
টিটোনি

7
এটি হ্যান্ডেল করার জন্য আপনি পলির মতো একটি ওপেন সোর্স লাইব্রেরি ব্যবহার করে দেখতে পারেন । পুনরায় চেষ্টাগুলির মধ্যে অপেক্ষা করার জন্য আরও অনেক নমনীয়তা রয়েছে এবং প্রকল্পটি ব্যবহার করেছেন এমন আরও অনেকে এটি দ্বারা বৈধতা পেয়েছে। উদাহরণ:Policy.Handle<DivideByZeroException>().WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3) });
টড মেইনশাগেন

220

আপনার পলি চেষ্টা করা উচিত । এটি আমার দ্বারা রচিত একটি নেট গ্রন্থাগার যা বিকাশকারীদের পুনরায় চেষ্টা, পুনরায় চেষ্টা করুন, অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন বা সার্কিট ব্রেকারের মতো অস্থায়ী ব্যতিক্রম হ্যান্ডলিং নীতিগুলি সাবলীল উপায়ে প্রকাশ করতে দেয়।

উদাহরণ

Policy
    .Handle<SqlException>(ex => ex.Number == 1205)
    .Or<ArgumentException>(ex => ex.ParamName == "example")
    .WaitAndRetry(3, retryAttempt => TimeSpan.FromSeconds(3))
    .Execute(() => DoSomething());

1
অনারেট্রি প্রতিনিধি আসলে কী? আমি ধরে নিই যে ব্যতিক্রম ঘটলে আমাদের এটি সম্পাদন করা প্রয়োজন। সুতরাং যখন ব্যতিক্রম ঘটে তখন অন-রেট্রি প্রতিনিধি কল করবে এবং তারপরে ডেলিগেটের সম্পাদন করবে। তাই নাকি?
ব্যবহারকারী 6395764

60

এটি সম্ভবত একটি খারাপ ধারণা। প্রথমত, এটি সর্বাধিকের প্রতীকী "পাগলের সংজ্ঞা একই জিনিস দু'বার করছে এবং প্রতিবার বিভিন্ন ফলাফলের প্রত্যাশা করছে"। দ্বিতীয়ত, এই কোডিং প্যাটার্নটি নিজের সাথে ভালভাবে রচনা করে না। উদাহরণ স্বরূপ:

মনে করুন আপনার নেটওয়ার্ক হার্ডওয়্যার স্তরটি ব্যর্থতার পরে তিনবার একটি প্যাকেট রিসেট করে, অপেক্ষা করুন, বলুন, ব্যর্থতার মধ্যে এক সেকেন্ড।

এখন ধরুন সফ্টওয়্যার স্তরটি প্যাকেট ব্যর্থতায় তিনবার ব্যর্থতা সম্পর্কে একটি বিজ্ঞপ্তি পুনরায় পাঠায়।

এখন ধরুন কোনও বিজ্ঞপ্তি সরবরাহ ব্যর্থতায় বিজ্ঞপ্তি স্তরটি তিনবার বিজ্ঞপ্তিটি পুনরায় সক্রিয় করে।

এখন ধরা যাক ত্রুটি প্রতিবেদন করার স্তরটি কোনও বিজ্ঞপ্তি ব্যর্থতায় তিনবার বিজ্ঞপ্তি স্তরটিকে পুনরায় সক্রিয় করে।

এবং এখন ধরা যাক ওয়েব সার্ভার ত্রুটি ব্যর্থ হওয়ার পরে তিনবার ত্রুটি প্রতিবেদন করার সময় ত্রুটিটি পুনরায় সক্রিয় করে।

এবং এখন ধরুন যে ওয়েব ক্লায়েন্টটি সার্ভার থেকে ত্রুটি পেয়ে তিনবার অনুরোধটি পুনরায় পাঠায়।

এখন ধরুন যে প্রশাসনের কাছে নোটিফিকেশনটি রুট করার কথা বলে এমন নেটওয়ার্কের স্যুইচটিতে থাকা লাইনটি আনপ্লাগড করা আছে। ওয়েব ক্লায়েন্টের ব্যবহারকারী শেষ পর্যন্ত তাদের ত্রুটি বার্তাটি পায়? আমি প্রায় বারো মিনিট পরে এটি তৈরি।

পাছে আপনি এটি কেবল একটি নির্বোধ উদাহরণ হিসাবে মনে করেন: আমরা এখানে বর্ণিত চেয়ে অনেক খারাপ হলেও গ্রাহক কোডে আমরা এই বাগটি দেখেছি। নির্দিষ্ট গ্রাহক কোডে, ত্রুটির শর্তটি ঘটছে এবং অবশেষে এটি ব্যবহারকারীকে জানানো হচ্ছে এর মধ্যে ব্যবধানটি কয়েক সপ্তাহ ছিল কারণ অনেক স্তর স্বয়ংক্রিয়ভাবে অপেক্ষা করে পুনরায় চেষ্টা করছে। তিনজনের পরিবর্তে দশটি চেষ্টা করা হলে কী হবে তা ভাবুন ।

সাধারণত ত্রুটির শর্তের সাথে সঠিক জিনিসটি তা অবিলম্বে জানানো হয় এবং ব্যবহারকারীকে সিদ্ধান্ত নিতে দিন। ব্যবহারকারী যদি স্বয়ংক্রিয় পুনরায় চেষ্টা করার নীতি তৈরি করতে চান, তবে তাদের সফ্টওয়্যার বিমূর্তিতে উপযুক্ত পর্যায়ে সেই নীতি তৈরি করতে দিন।


19
+1 টি। রেমন্ড এখানে একটি বাস্তব জীবনের উদাহরণ ভাগ করেছেন, ব্লগস.এমএসএনএন
সমাধান

210
-1 স্বয়ংক্রিয় ব্যাচ প্রসেসিং সিস্টেমগুলির দ্বারা অস্থায়ী নেটওয়ার্ক ব্যর্থতার জন্য এই পরামর্শটি অকেজো।
21-22 এ

15
নিশ্চিত না যে এটি "এটি করবেন না" এর পরে "এটি করবেন" বলছে কিনা। এই প্রশ্নটি জিজ্ঞাসা করা বেশিরভাগ লোকই সম্ভবত সফ্টওয়্যার বিমূর্তকরণে কাজ করা লোক।
জিম এল

44
যখন আপনার দীর্ঘকাল ধরে চলমান ব্যাচ কাজগুলি রয়েছে যা নেটওয়ার্ক পরিষেবাদি যেমন ওয়েব পরিষেবাদি ব্যবহার করে, আপনি নেটওয়ার্কটি 100% নির্ভরযোগ্য হওয়ার আশা করতে পারবেন না। মাঝেমধ্যে সময়সীমা, সকেট সংযোগ বিচ্ছিন্ন হতে পারে, সম্ভবত আপনি এটি ব্যবহার করার সময় ঘটে যাওয়া রুচির গ্লিটস বা সার্ভার বিভ্রাট ঘটে। একটি বিকল্প হ'ল ব্যর্থ হওয়া, তবে এর অর্থ পরে একটি দীর্ঘ কাজ পুনরায় চালু করা হতে পারে। অন্য বিকল্পটি হ'ল এটি কোনও অস্থায়ী সমস্যা কিনা তা দেখার জন্য উপযুক্ত বিলম্বের সাথে কয়েকবার চেষ্টা করার পরে ব্যর্থ হন। আমি রচনা সম্পর্কে একমত, যা আপনাকে সচেতন হতে হবে .. তবে এটি কখনও কখনও সেরা পছন্দ।
এরিক ফানকেনবাশ

18
আমি মনে করি আপনি আপনার উত্তরের শুরুতে যে উক্তিটি ব্যবহার করেছিলেন তা আকর্ষণীয়। "ভিন্ন ফলাফল প্রত্যাশা করা" কেবলমাত্র উন্মাদনা যদি পূর্ব অভিজ্ঞতা নিয়মিত আপনাকে একই ফলাফল দেয়। সফ্টওয়্যারটি ধারাবাহিকতার প্রতিশ্রুতিতে তৈরি করা হলেও, এমন পরিস্থিতি অবশ্যই রয়েছে যেখানে আমাদের নিয়ন্ত্রণের বাইরে অবিশ্বাস্য শক্তির সাথে যোগাযোগ করতে হবে।
মাইকেল রিচার্ডসন

49
public void TryThreeTimes(Action action)
{
    var tries = 3;
    while (true) {
        try {
            action();
            break; // success!
        } catch {
            if (--tries == 0)
                throw;
            Thread.Sleep(1000);
        }
    }
}

তাহলে আপনি কল করবেন:

TryThreeTimes(DoSomething);

... বা বিকল্পভাবে ...

TryThreeTimes(() => DoSomethingElse(withLocalVariable));

আরও নমনীয় বিকল্প:

public void DoWithRetry(Action action, TimeSpan sleepPeriod, int tryCount = 3)
{
    if (tryCount <= 0)
        throw new ArgumentOutOfRangeException(nameof(tryCount));

    while (true) {
        try {
            action();
            break; // success!
        } catch {
            if (--tryCount == 0)
                throw;
            Thread.Sleep(sleepPeriod);
        }
   }
}

হিসাবে ব্যবহার করা হবে:

DoWithRetry(DoSomething, TimeSpan.FromSeconds(2), tryCount: 10);

অ্যাসিঙ্ক / অপেক্ষার জন্য সমর্থন সহ আরও একটি আধুনিক সংস্করণ:

public async Task DoWithRetryAsync(Func<Task> action, TimeSpan sleepPeriod, int tryCount = 3)
{
    if (tryCount <= 0)
        throw new ArgumentOutOfRangeException(nameof(tryCount));

    while (true) {
        try {
            await action();
            return; // success!
        } catch {
            if (--tryCount == 0)
                throw;
            await Task.Delay(sleepPeriod);
        }
   }
}

হিসাবে ব্যবহার করা হবে:

await DoWithRetryAsync(DoSomethingAsync, TimeSpan.FromSeconds(2), tryCount: 10);

2
অগ্রাধিকার হিসাবে if টি পরিবর্তন করুন: --retryCount <= 0কারণ আপনি যদি 0 এ retryCountসেট করে পুনরায় চেষ্টা অক্ষম করতে চান তবে এটি চিরতরে চলে যাবে প্রযুক্তিগতভাবে শব্দটি আসলেই খুব ভাল নাম নয়, কারণ আপনি এটি 1 এ সেট করে থাকলে এটি পুনরায় চেষ্টা করবে না হয় হয় নতুন নাম পরিবর্তন করুন either এটিতে tryCountবা রাখুন - পিছনে।
স্টিফানভিডস

2
@ সেলেল আমি সম্মত তবে ওপি (এবং অন্যান্য সমস্ত উত্তর) ব্যবহার করছে Thread.Sleep। বিকল্পগুলি হ'ল টাইমার ব্যবহার করা বা সম্ভবত আজকাল asyncপুনরায় চেষ্টা করার জন্য আরও বেশি কিছু সম্ভবত ব্যবহার করা Task.Delay
ড্র নোকস

2
আমি একটি অ্যাসিঙ্ক সংস্করণ যুক্ত করেছি।
ড্র নোকস

শুধু যদি বিরতি হয় কর্ম returns true? Func<bool>
কিকিনেট

32

অস্থায়ী ফল্ট হ্যান্ডলিং অ্যাপ্লিকেশন ব্লক সহ পুনরায় চেষ্টা কৌশল একটি প্রসার্য সংগ্রহে প্রদান করে:

  • ক্রমবর্ধমান
  • স্থির বিরতি
  • ঘৃণ্য ব্যাক-অফ off

এটিতে ক্লাউড-ভিত্তিক পরিষেবার জন্য ত্রুটি সনাক্তকরণ কৌশলগুলির সংগ্রহও অন্তর্ভুক্ত রয়েছে।

আরও তথ্যের জন্য এই অধ্যায়টি দেখুন জন্য বিকাশকারীদের গাইডের ।

নুগেটের মাধ্যমে উপলব্ধ (' পোখরাজ ' অনুসন্ধান করুন )।


1
মজাদার. আপনি কি উইন্ডোজ অ্যাজুরে এর বাইরে ব্যবহার করতে পারেন, উইনফর্মস অ্যাপ্লিকেশনটিতে বলুন?
ম্যাথু লক

6
একেবারে। মূল পুনরায় চেষ্টা করার পদ্ধতিটি ব্যবহার করুন এবং আপনার নিজের সনাক্তকরণ কৌশলগুলি সরবরাহ করুন। আমরা ইচ্ছাকৃতভাবে তাদের decoupled। মূল নুগেট প্যাকেজটি এখানে সন্ধান করুন: nuget.org/packages/TransientFaultHandling.Core
গ্রিগরি

2
এছাড়াও, প্রকল্পটি এখন অ্যাপাচি ২.০ এর অধীনে এবং সম্প্রদায়ের অবদান গ্রহণ করছে। aka.ms/entlibopen
গ্রিগোরি মেলনিক

1
@Alex। এর টুকরো এটিকে প্ল্যাটফর্মে তৈরি করছে into
গ্রিগোরি মেলানিক

2
এটি এখন অবচয় করা হয়েছে, এবং সর্বশেষে আমি এটি ব্যবহার করেছি এটিতে কিছু বাগ রয়েছে যা আমি জানি যতদূর জানা ছিল না এবং কখনও ঠিক করা হবে না: github.com/Mic MicrosoftArchive/…
ওহাদ স্নাইডার

15

ফাংশনগুলির জন্য এবং বার্তাগুলির পুনরায় চেষ্টা করার অনুমতি দেওয়া হচ্ছে

public static T RetryMethod<T>(Func<T> method, int numRetries, int retryTimeout, Action onFailureAction)
{
 Guard.IsNotNull(method, "method");            
 T retval = default(T);
 do
 {
   try
   {
     retval = method();
     return retval;
   }
   catch
   {
     onFailureAction();
      if (numRetries <= 0) throw; // improved to avoid silent failure
      Thread.Sleep(retryTimeout);
   }
} while (numRetries-- > 0);
  return retval;
}

RetryMethod করার retval সত্য, বাmax retries?
কিকিনেট

14

আপনি যে ব্যতিক্রমের জন্য পুনরায় চেষ্টা করতে চান সেটি যোগ করার বিষয়টিও বিবেচনা করতে পারেন। উদাহরণস্বরূপ, আপনি কি আবার চেষ্টা করতে চান এটি একটি সময়সাপেক্ষ ব্যতিক্রম? একটি ডাটাবেস ব্যতিক্রম?

RetryForExcpetionType(DoSomething, typeof(TimeoutException), 5, 1000);

public static void RetryForExcpetionType(Action action, Type retryOnExceptionType, int numRetries, int retryTimeout)
{
    if (action == null)
        throw new ArgumentNullException("action");
    if (retryOnExceptionType == null)
        throw new ArgumentNullException("retryOnExceptionType");
    while (true)
    {
        try
        {
            action();
            return;
        }
        catch(Exception e)
        {
            if (--numRetries <= 0 || !retryOnExceptionType.IsAssignableFrom(e.GetType()))
                throw;

            if (retryTimeout > 0)
                System.Threading.Thread.Sleep(retryTimeout);
        }
    }
}

আপনি আরও লক্ষ করতে পারেন যে অন্যান্য উদাহরণগুলির মধ্যে পুনরায় চেষ্টা == 0 পরীক্ষা করার ক্ষেত্রে একই সমস্যা রয়েছে এবং অনন্তর চেষ্টা করে দেখুন বা নেতিবাচক মান দেওয়ার পরে ব্যতিক্রম বাড়াতে ব্যর্থ হন। এছাড়াও ঘুম (-1000) উপরের ক্যাচ ব্লকে ব্যর্থ হবে। আপনি কীভাবে 'নির্বুদ্ধ' হন তা নির্ভর করে আপনি কীভাবে মানুষের প্রত্যাশা করেন কিন্তু ডিফেন্সিভ প্রোগ্রামিং কখনই ব্যাথা করে না।


9
+1, তবে কেন টি টি: ব্যতিক্রম, তারপরে (টি ই) ধরুন <T> (...) পুনরায় চেষ্টা করবেন না? এটি চেষ্টা করে দেখুন এবং এটি নিখুঁতভাবে কাজ করে।
ট্রুউইল

হয় বা এখানে যেহেতু আমার প্রকারের সাথে কিছু করার দরকার নেই তবে শর্ত রয়েছে যে আমি বুঝতে পেরেছি যে একটি সাধারণ পুরানো প্যারামিটারটি কৌশলটি করতে পারে।
csharptest.net

দৃশ্যত ধরা @TrueWill (টি প্রাক্তন) এই পোস্টে অনুযায়ী কিছু বাগ আছে stackoverflow.com/questions/1577760/...
csharptest.net

3
আপডেট: আসলে আমি ব্যবহার করছি আরও ভাল প্রয়োগের জন্য একটি প্রেডিকেট <এক্সেকশন> প্রতিনিধি লাগে যা একটি পুনরায় চেষ্টা করা উপযুক্ত হলে সত্য ফিরে আসে। এটি আপনাকে পুনরায় চেষ্টা প্রযোজ্য কিনা তা নির্ধারণ করতে নেটিভ ত্রুটি কোডগুলি বা ব্যতিক্রমের অন্যান্য বৈশিষ্ট্যগুলি ব্যবহার করার অনুমতি দেয়। উদাহরণস্বরূপ HTTP 503 কোড।
csharptest.net

1
"এছাড়াও ঘুম (-1000) উপরের ক্যাচ ব্লকে ব্যর্থ হবে" ... একটি টাইমস্প্যান ব্যবহার করুন এবং আপনি এই সমস্যাটি পাবেন না। প্লাস টাইমস্প্যান অনেক বেশি নমনীয় এবং স্ব বর্ণনামূলক। আপনার "int retryTimeout" এর স্বাক্ষর থেকে আমি কীভাবে জানতে পারি যে retryTimeout এমএস, সেকেন্ড, মিনিট, বছর হয় কিনা ?? ;-)
বাইটেদেভ

13

আমি পুনরাবৃত্তি এবং এক্সটেনশন পদ্ধতিগুলির অনুরাগী, সুতরাং আমার দুটি সেন্ট এখানে রয়েছে:

public static void InvokeWithRetries(this Action @this, ushort numberOfRetries)
{
    try
    {
        @this();
    }
    catch
    {
        if (numberOfRetries == 0)
            throw;

        InvokeWithRetries(@this, --numberOfRetries);
    }
}

7

পূর্ববর্তী কাজের উপর ভিত্তি করে, আমি তিনটি উপায়ে পুনরায় চেষ্টা যুক্তি বাড়ানোর বিষয়ে চিন্তা করেছি:

  1. ধরতে / পুনরায় চেষ্টা করতে কোন ব্যতিক্রম প্রকার তা নির্দিষ্ট করে। কোনও ব্যাতিক্রমের জন্য পুনরায় চেষ্টা করা কেবল সাধারণ ভুল হিসাবে এটি এটি প্রাথমিক উত্সাহ।
  2. চেষ্টা / ধরাতে সর্বশেষ চেষ্টাটি বাসা বাঁধছে না, কিছুটা ভাল পারফরম্যান্স অর্জন করছে
  3. এটিকে একটি Actionএক্সটেনশন পদ্ধতি হিসাবে তৈরি করা হচ্ছে

    static class ActionExtensions
    {
      public static void InvokeAndRetryOnException<T> (this Action action, int retries, TimeSpan retryDelay) where T : Exception
      {
        if (action == null)
          throw new ArgumentNullException("action");
    
        while( retries-- > 0 )
        {
          try
          {
            action( );
            return;
          }
          catch (T)
          {
            Thread.Sleep( retryDelay );
          }
        }
    
        action( );
      }
    }

পদ্ধতিটি তখন অনুরোধ করা যেতে পারে (বেনাম পদ্ধতিগুলি অবশ্যই ব্যবহার করা যেতে পারে):

new Action( AMethodThatMightThrowIntermittentException )
  .InvokeAndRetryOnException<IntermittentException>( 2, TimeSpan.FromSeconds( 1 ) );

1
এটি দুর্দান্ত। তবে ব্যক্তিগতভাবে আমি এটিকে 'পুনরায় টাইমআউট' বলব না কারণ এটি আসলে সময়সাপেক্ষ নয়। 'রিট্রিডিলে', সম্ভবত?
হোল্ফ

7

এটি সি # 6.0 দিয়ে সাধারণ রাখুন

public async Task<T> Retry<T>(Func<T> action, TimeSpan retryInterval, int retryCount)
{
    try
    {
        return action();
    }
    catch when (retryCount != 0)
    {
        await Task.Delay(retryInterval);
        return await Retry(action, retryInterval, --retryCount);
    }
}

2
আমি এক ধরণের কৌতূহলী, একই প্রতীক্ষিত পদ্ধতিতে ফিরে আসার কারণে এটি কি আবার চেষ্টা করার জন্য একটি উচ্চ পুনরায় চেষ্টা এবং ব্যবধানের সাথে একটি উন্মাদ পরিমাণ থ্রেড তৈরি করবে?
হান্টকে 24

6

পলি ব্যবহার করুন

https://github.com/App-vNext/Polly-Samples

আমি এখানে পলির সাথে পুনরায় চেষ্টা করার চেষ্টা করেছি

public T Retry<T>(Func<T> action, int retryCount = 0)
{
    PolicyResult<T> policyResult = Policy
     .Handle<Exception>()
     .Retry(retryCount)
     .ExecuteAndCapture<T>(action);

    if (policyResult.Outcome == OutcomeType.Failure)
    {
        throw policyResult.FinalException;
    }

    return policyResult.Result;
}

এটি ব্যবহার করুন

var result = Retry(() => MyFunction()), 3);

5

সর্বশেষ ফ্যাশনে এল বুশকিনের উত্তর প্রয়োগ করেছেন:

    public static async Task Do(Func<Task> task, TimeSpan retryInterval, int maxAttemptCount = 3)
    {
        var exceptions = new List<Exception>();
        for (int attempted = 0; attempted < maxAttemptCount; attempted++)
        {
            try
            {
                if (attempted > 0)
                {
                    await Task.Delay(retryInterval);
                }

                await task();
                return;
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }
        }
        throw new AggregateException(exceptions);
    }

    public static async Task<T> Do<T>(Func<Task<T>> task, TimeSpan retryInterval, int maxAttemptCount = 3)
    {
        var exceptions = new List<Exception>();
        for (int attempted = 0; attempted < maxAttemptCount; attempted++)
        {
            try
            {
                if (attempted > 0)
                {
                    await Task.Delay(retryInterval);
                }
                return await task();
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }
        }
        throw new AggregateException(exceptions);
    }  

এবং এটি ব্যবহার করতে:

await Retry.Do([TaskFunction], retryInterval, retryAttempts);

ফাংশন [TaskFunction]হয় হয় Task<T>বা ন্যায়বিচার হতে পারে Task


1
ধন্যবাদ, ফ্যাবিয়ান! এটি শীর্ষে সমস্ত উপায়ে upvated করা উচিত!
জেমসহক্স

1
@ মার্কলাউটারের সংক্ষিপ্ত উত্তরটি হ্যাঁ। ;-)
ফ্যাবিয়ান বিগলার

4

আমি এটি বাস্তবায়ন করব:

public static bool Retry(int maxRetries, Func<bool, bool> method)
{
    while (maxRetries > 0)
    {
        if (method(maxRetries == 1))
        {
            return true;
        }
        maxRetries--;
    }
    return false;        
}

আমি অন্যান্য উদাহরণগুলিতে যেভাবে ব্যতিক্রম হয় সেগুলি ব্যবহার করব না। আমার কাছে মনে হয়েছে যে আমরা যদি কোনও পদ্ধতি সফল না হওয়ার সম্ভাবনাটি আশা করি তবে এর ব্যর্থতা ব্যতিক্রম নয়। সুতরাং যে পদ্ধতিটি আমি কল করছি তা যদি সফল হয় তবে সত্য হওয়া উচিত, এবং এটি ব্যর্থ হলে মিথ্যা।

কেন এটি একটি Func<bool, bool>এবং কেবল একটি নয় Func<bool>? যাতে আমি যদি কোনও পদ্ধতি ব্যর্থতার ক্ষেত্রে একটি ব্যতিক্রম ছুঁড়ে ফেলতে সক্ষম হতে চাই তবে আমার এটি জানাতে একটি উপায় আছে যে এটিই শেষ চেষ্টা।

সুতরাং আমি কোড সহ এটি ব্যবহার করতে পারে:

Retry(5, delegate(bool lastIteration)
   {
       // do stuff
       if (!succeeded && lastIteration)
       {
          throw new InvalidOperationException(...)
       }
       return succeeded;
   });

অথবা

if (!Retry(5, delegate(bool lastIteration)
   {
       // do stuff
       return succeeded;
   }))
{
   Console.WriteLine("Well, that didn't work.");
}

যদি একটি প্যারামিটার যে পদ্ধতি ব্যবহার বিশ্রী হতে প্রমাণ নেই ক্ষণস্থায়ী, এটা একজন জমিদার বাস্তবায়ন তুচ্ছ ব্যাপার Retryমাত্র লাগে যে Func<bool>হিসাবে ভাল।


1
ব্যতিক্রম এড়ানোর জন্য +1। যদিও আমি একটি অকার্যকর চেষ্টা করব (...) এবং কিছু ফেলেছি? বুলিয়ান রিটার্ন এবং / অথবা রিটার্ন কোডগুলি প্রায়শই উপেক্ষা করা হয়।
csharptest.net

1
"যদি আমরা সম্ভাবনাটি আশা করি যে কোনও পদ্ধতি সফল হবে না, তবে এর ব্যর্থতা ব্যতিক্রম নয়" - যদিও এটি কিছু ক্ষেত্রে সত্য, ব্যতিক্রম ব্যতিক্রমী বোঝার দরকার নেই। এটি ত্রুটি পরিচালনার জন্য। কলার কোনও বুলিয়ান ফলাফল যাচাই করবে এমন কোনও গ্যারান্টি নেই। সেখানে হয় একটি গ্যারান্টি যে একটি ব্যতিক্রম পরিচালিত হবে (রানটাইম আবেদন যদি কিছুই অন্যথায় করে শাট ডাউন দ্বারা)।
ট্রুউইল

আমি রেফারেন্সটি খুঁজে পাই না তবে আমি বিশ্বাস করি। নেট একটি ব্যাতিক্রমকে "একটি পদ্ধতি যা বলেছিল এটি করবে না" হিসাবে একটি ব্যতিক্রমকে সংজ্ঞায়িত করে। 1 উদ্দেশ্য হ'ল ফোনটি ফাংশনটি সফল হয়েছে কি না সফল হয়েছে কিনা তা ফেরতের মান যাচাই করার জন্য কলকারীকে উইন 32 প্যাটার্নের পরিবর্তে কোনও সমস্যা নির্দেশ করতে ব্যতিক্রমগুলি ব্যবহার করা।
noctonura

তবে ব্যতিক্রমগুলি কেবল "সমস্যা নির্দেশ করে" don't এগুলি ডায়াগনস্টিক তথ্যের একটি বৃহত্তর অন্তর্ভুক্ত যা সংকলন করতে সময় এবং মেমরির ব্যয় করে। কিছুটা স্পষ্ট পরিস্থিতি রয়েছে এতে সামান্য কিছুটা হলেও আসে যায় না। তবে সেখানে অনেক কিছুই রয়েছে। .NET নিয়ন্ত্রণ প্রবাহের জন্য ব্যতিক্রমগুলি ব্যবহার করে না (পাইথনের StopIterationব্যতিক্রমটি ব্যবহারের সাথে তুলনা করুন, বলুন ), এবং এর একটি কারণ রয়েছে।
রবার্ট রসনি

TryDoপদ্ধতি প্যাটার্ন একটি পিচ্ছিল ঢাল নেই। এটি জানার আগে, আপনার সম্পূর্ণ কল স্ট্যাক TryDoপদ্ধতিতে থাকবে। এই জাতীয় গোলযোগ এড়াতে ব্যতিক্রমগুলি আবিষ্কার করা হয়েছিল ceptions
শুভনোমাদ


2

যারা কোনও ব্যতিক্রম নিয়ে পুনরায় চেষ্টা করতে বা স্পষ্টভাবে ব্যতিক্রম প্রকার সেট করতে চান তাদের উভয়ই এই বিকল্পটি ব্যবহার করুন:

public class RetryManager 
{
    public void Do(Action action, 
                    TimeSpan interval, 
                    int retries = 3)
    {
        Try<object, Exception>(() => {
            action();
            return null;
        }, interval, retries);
    }

    public T Do<T>(Func<T> action, 
                    TimeSpan interval, 
                    int retries = 3)
    {
        return Try<T, Exception>(
              action
            , interval
            , retries);
    }

    public T Do<E, T>(Func<T> action, 
                       TimeSpan interval, 
                       int retries = 3) where E : Exception
    {
        return Try<T, E>(
              action
            , interval
            , retries);
    }

    public void Do<E>(Action action, 
                       TimeSpan interval, 
                       int retries = 3) where E : Exception
    {
        Try<object, E>(() => {
            action();
            return null;
        }, interval, retries);
    }

    private T Try<T, E>(Func<T> action, 
                       TimeSpan interval, 
                       int retries = 3) where E : Exception
    {
        var exceptions = new List<E>();

        for (int retry = 0; retry < retries; retry++)
        {
            try
            {
                if (retry > 0)
                    Thread.Sleep(interval);
                return action();
            }
            catch (E ex)
            {
                exceptions.Add(ex);
            }
        }

        throw new AggregateException(exceptions);
    }
}

2

আমার এমন একটি পদ্ধতির দরকার ছিল যা বাতিলকরণকে সমর্থন করে, আমি যখন ছিলাম তখন আমি অন্তর্বর্তী ব্যর্থতা ফিরিয়ে দেওয়ার জন্য সমর্থন যোগ করেছি।

public static class ThreadUtils
{
    public static RetryResult Retry(
        Action target,
        CancellationToken cancellationToken,
        int timeout = 5000,
        int retries = 0)
    {
        CheckRetryParameters(timeout, retries)
        var failures = new List<Exception>();
        while(!cancellationToken.IsCancellationRequested)
        {
            try
            {
                target();
                return new RetryResult(failures);
            }
            catch (Exception ex)
            {
                failures.Add(ex);
            }

            if (retries > 0)
            {
                retries--;
                if (retries == 0)
                {
                    throw new AggregateException(
                     "Retry limit reached, see InnerExceptions for details.",
                     failures);
                }
            }

            if (cancellationToken.WaitHandle.WaitOne(timeout))
            {
                break;
            }
        }

        failures.Add(new OperationCancelledException(
            "The Retry Operation was cancelled."));
        throw new AggregateException("Retry was cancelled.", failures);
    }

    private static void CheckRetryParameters(int timeout, int retries)
    {
        if (timeout < 1)
        {
            throw new ArgumentOutOfRangeException(...
        }

        if (retries < 0)
        {
            throw new ArgumentOutOfRangeException(...

        }
    }

    public class RetryResult : IEnumerable<Exception>
    {
        private readonly IEnumerable<Exception> failureExceptions;
        private readonly int failureCount;

         protected internal RetryResult(
             ICollection<Exception> failureExceptions)
         {
             this.failureExceptions = failureExceptions;
             this.failureCount = failureExceptions.Count;
         }
    }

    public int FailureCount
    {
        get { return this.failureCount; }
    }

    public IEnumerator<Exception> GetEnumerator()
    {
        return this.failureExceptions.GetEnumerator();
    }

    System.Collections.IEnumerator 
        System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

আপনি এইভাবে Retryফাংশনটি ব্যবহার করতে পারেন , 10 সেকেন্ড বিলম্বের সাথে 3 বার পুনরায় চেষ্টা করুন কিন্তু বাতিল না করে।

try
{
    var result = ThreadUtils.Retry(
        SomeAction, 
        CancellationToken.None,
        10000,
        3);

    // it worked
    result.FailureCount // but failed this many times first.
}
catch (AggregationException ex)
{
   // oops, 3 retries wasn't enough.
}

অথবা, বাতিল না হলে প্রতি পাঁচ সেকেন্ডে চিরতরে চেষ্টা করুন।

try
{
    var result = ThreadUtils.Retry(
        SomeAction, 
        someTokenSource.Token);

    // it worked
    result.FailureCount // but failed this many times first.
}
catch (AggregationException ex)
{
   // operation was cancelled before success.
}

আপনি অনুমান করতে পারেন, আমার উত্স কোডে আমি Retryব্যবহার করতে ইচ্ছুক বিভিন্ন বদ্বীপ প্রকার সমর্থন করতে ফাংশনটি ওভারলোড করেছি ।


2

এই পদ্ধতিটি কিছু ব্যতিক্রম প্রকারের (আবার অন্যকে অবিলম্বে নিক্ষেপ করে) পুনরায় চেষ্টা করার অনুমতি দেয়।

public static void DoRetry(
    List<Type> retryOnExceptionTypes,
    Action actionToTry,
    int retryCount = 5,
    int msWaitBeforeEachRety = 300)
{
    for (var i = 0; i < retryCount; ++i)
    {
        try
        {
            actionToTry();
            break;
        }
        catch (Exception ex)
        {
            // Retries exceeded
            // Throws on last iteration of loop
            if (i == retryCount - 1) throw;

            // Is type retryable?
            var exceptionType = ex.GetType();
            if (!retryOnExceptionTypes.Contains(exceptionType))
            {
                throw;
            }

            // Wait before retry
            Thread.Sleep(msWaitBeforeEachRety);
        }
    }
}
public static void DoRetry(
    Type retryOnExceptionType,
    Action actionToTry,
    int retryCount = 5,
    int msWaitBeforeEachRety = 300)
        => DoRetry(new List<Type> {retryOnExceptionType}, actionToTry, retryCount, msWaitBeforeEachRety);

ব্যবহারের উদাহরণ:

DoRetry(typeof(IOException), () => {
    using (var fs = new FileStream(requestedFilePath, FileMode.Create, FileAccess.Write))
    {
        fs.Write(entryBytes, 0, entryBytes.Length);
    }
});

1

6 বছর পরে আপডেট: এখন আমি বিবেচনা করি যে নীচের পদ্ধতিরটি বেশ খারাপ। পুনরায় চেষ্টা করার যুক্তি তৈরি করতে আমাদের পলির মতো একটি লাইব্রেরি ব্যবহার করা উচিত।


আমার asyncপুনরায় চেষ্টা পদ্ধতি বাস্তবায়ন:

public static async Task<T> DoAsync<T>(Func<dynamic> action, TimeSpan retryInterval, int retryCount = 3)
    {
        var exceptions = new List<Exception>();

        for (int retry = 0; retry < retryCount; retry++)
        {
            try
            {
                return await action().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }

            await Task.Delay(retryInterval).ConfigureAwait(false);
        }
        throw new AggregateException(exceptions);
    }

মূল বিষয়: আমি ব্যবহার করেছি .ConfigureAwait(false);এবং Func<dynamic>পরিবর্তেFunc<T>


এটি প্রশ্নের উত্তর সরবরাহ করে না। পৃষ্ঠার শীর্ষে "প্রশ্ন জিজ্ঞাসা করুন" বোতামটি ব্যবহার করে আপনার উত্তরটি নতুন প্রশ্ন হিসাবে পোস্ট করার বিষয়ে বিবেচনা করুন এবং তারপরে আপনি কী শিখেছেন তা সম্প্রদায়ের সাথে ভাগ করে নেওয়ার জন্য প্রশ্নের নিজের উত্তর পোস্ট করুন।
এলিক্সনাইড

কোডেরভিউ.স্ট্যাকেক্সেঞ্জা.কম / কিউ / ৫৯83৮83৩ / ৫৪০০০ এর চেয়ে সি # 5.0 সহ অনেক সহজ তবে সম্ভবত ক্যানসেলেকশন টোকেন ইনজেকশন দেওয়া উচিত।
সার্জ

এই বাস্তবায়নে সমস্যা আছে। চূড়ান্ত পুনরায় চেষ্টা করার পরে, হাল ছাড়ার আগে, Task.Delayবিনা কারণে ডাকা হয়।
শুভনোমাদ

@ হ্যাপি নোমাদ এটি একটি 6 বছরের পুরানো উত্তর এবং এখন আমি বিবেচনা করেছি যে এটি পুনরায় চেষ্টা করার যুক্তি তৈরি করার জন্য এটি একটি খুব খারাপ পদ্ধতি :)) বিজ্ঞপ্তির জন্য ধন্যবাদ। আমি সেই বিবেচনা অনুযায়ী আমার উত্তর আপডেট করব।
সিহান উগুন

0

অথবা কীভাবে এটি কিছুটা নিবিড়ভাবে করা যায় ...

int retries = 3;
while (retries > 0)
{
  if (DoSomething())
  {
    retries = 0;
  }
  else
  {
    retries--;
  }
}

আমি বিশ্বাস করি যে ছড়িয়ে দেওয়া ব্যতিক্রমগুলি সাধারণত একটি প্রক্রিয়া হিসাবে এড়ানো উচিত যদি না আপনার সীমানাগুলির মধ্যে পাস করা হয় (যেমন একটি লাইব্রেরি তৈরি করা যেমন অন্যান্য লোকেরা ব্যবহার করতে পারে)। সফল এবং অন্যথায় যদি DoSomething()কমান্ডটি কেবল ফিরে আসে না কেন ?truefalse

সম্পাদনা: এবং এটি অন্যদের মতো প্রস্তাবিত মত একটি ফাংশন ভিতরে আবৃত করা যেতে পারে। শুধুমাত্র সমস্যাটি যদি আপনি DoSomething()নিজে ফাংশনটি না লিখছেন


7
"আমি বিশ্বাস করি যে ছোঁড়া ব্যতিক্রমগুলি সাধারণত একটি প্রক্রিয়া হিসাবে এড়ানো উচিত যদি না আপনি তাদের সীমানার মধ্যে দিয়ে চলে যান" - আমি সম্পূর্ণরূপে একমত নই। আপনি কীভাবে জানেন যে ফোনকারী আপনার মিথ্যা (বা আরও খারাপ, নাল) ফেরত পরীক্ষা করেছে? কোডটি কেন ব্যর্থ হয়েছিল? মিথ্যা আপনাকে আর কিছুই বলে না। যদি কলকারীকে ব্যর্থতাটি স্ট্যাকের মধ্যে দিয়ে যেতে হয় তবে কী হবে? এমএসডিএন.মাইক্রোসফট.এইনএস / লাইব্রেরি / এমস 229014.aspx পড়ুন - এগুলি গ্রন্থাগারগুলির জন্য, তবে তারা অভ্যন্তরীণ কোডের জন্য ঠিক ততটা অর্থবোধ করে । এবং একটি দলে, অন্যান্য লোকেরা আপনার কোডটি কল করতে পারে।
ট্রুউইল

0

পুনরায় চেষ্টা করার জন্য আমার পদ্ধতিতে আমার কিছু প্যারামিটার পাস করার প্রয়োজন ছিল এবং ফলাফলের মানও ছিল; সুতরাং আমার একটি অভিব্যক্তি প্রয়োজন .. আমি এই ক্লাসটি তৈরি করি যা কাজ করে (এটি এল বুশকিনের দ্বারা অনুপ্রাণিত হয়) আপনি এটি ব্যবহার করতে পারেন:

static void Main(string[] args)
{
    // one shot
    var res = Retry<string>.Do(() => retryThis("try"), 4, TimeSpan.FromSeconds(2), fix);

    // delayed execute
    var retry = new Retry<string>(() => retryThis("try"), 4, TimeSpan.FromSeconds(2), fix);
    var res2 = retry.Execute();
}

static void fix()
{
    Console.WriteLine("oh, no! Fix and retry!!!");
}

static string retryThis(string tryThis)
{
    Console.WriteLine("Let's try!!!");
    throw new Exception(tryThis);
}

public class Retry<TResult>
{
    Expression<Func<TResult>> _Method;
    int _NumRetries;
    TimeSpan _RetryTimeout;
    Action _OnFailureAction;

    public Retry(Expression<Func<TResult>> method, int numRetries, TimeSpan retryTimeout, Action onFailureAction)
    {
        _Method = method;
        _NumRetries = numRetries;
        _OnFailureAction = onFailureAction;
        _RetryTimeout = retryTimeout;
    }

    public TResult Execute()
    {
        TResult result = default(TResult);
        while (_NumRetries > 0)
        {
            try
            {
                result = _Method.Compile()();
                break;
            }
            catch
            {
                _OnFailureAction();
                _NumRetries--;
                if (_NumRetries <= 0) throw; // improved to avoid silent failure
                Thread.Sleep(_RetryTimeout);
            }
        }
        return result;
    }

    public static TResult Do(Expression<Func<TResult>> method, int numRetries, TimeSpan retryTimeout, Action onFailureAction)
    {
        var retry = new Retry<TResult>(method, numRetries, retryTimeout, onFailureAction);
        return retry.Execute();
    }
}

পুনশ্চ. এল বুশকিনের সমাধান আরও একবার চেষ্টা করে = ডি


0

আমি গৃহীত উত্তরের সাথে নিম্নলিখিত কোডটি যুক্ত করব

public static class Retry<TException> where TException : Exception //ability to pass the exception type
    {
        //same code as the accepted answer ....

        public static T Do<T>(Func<T> action, TimeSpan retryInterval, int retryCount = 3)
        {
            var exceptions = new List<Exception>();

            for (int retry = 0; retry < retryCount; retry++)
            {
                try
                {
                    return action();
                }
                catch (TException ex) //Usage of the exception type
                {
                    exceptions.Add(ex);
                    Thread.Sleep(retryInterval);
                }
            }

            throw new AggregateException(String.Format("Failed to excecute after {0} attempt(s)", retryCount), exceptions);
        }
    }

মূলত উপরের কোডটি তৈরি করছে Retry ক্লাসটিকে জেনেরিক করে তুলছে যাতে আপনি পুনরায় চেষ্টা করার জন্য যে ব্যতিক্রমটি ধরতে চান সেই ধরণের পাস করতে পারেন।

এখন এটি প্রায় একইভাবে ব্যবহার করুন তবে ব্যতিক্রমের ধরণ উল্লেখ করুন

Retry<EndpointNotFoundException>.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1));

ফর লুপ সর্বদা বেশ কয়েকবার কার্যকর করা হবে (আপনার পুনরায় চেষ্টাের ভিত্তিতে) এমনকি যদি ব্যতীত ট্রাই ক্যাচ লুপের কোডটি কার্যকর করা হয়। আমি চেষ্টা করব লুপের মধ্যে পুনরায় চেষ্টা করার সমান retryCount সেট করার পরামর্শ, যাতে লুপ উইল এটির উপর দিয়ে যাওয়া বন্ধ করে দেয়।
স্ক্রিন_উজব

@scre_www আমি বিশ্বাস করি আপনি ভুল করেছেন। যদি actionনিক্ষেপ না করে তবে লুপ থেকে দূরে Doএইভাবে ফিরে আসে । breakfor
শুভনোমাদ

যাই হোক না কেন, এই বাস্তবায়নে সমস্যা আছে। চূড়ান্ত পুনরায় চেষ্টা করার পরে, হাল ছাড়ার আগে, Thread.Sleepবিনা কারণে ডাকা হয়।
শুভনোমাদ

0

আমি জানি এই উত্তরটি খুব পুরানো তবে আমি এই বিষয়ে মন্তব্য করতে চেয়েছিলাম কারণ কাউন্টারগুলির সাথে যা কিছু করা হোক না কেন, করার সময় আমি এইগুলি ব্যবহার করে সমস্যার মধ্যে পড়েছি।

কয়েক বছর ধরে আমি আরও ভাল পদ্ধতির উপর স্থির হয়েছি বলে আমি মনে করি। এটি একটি ক্রিয়াকলাপের এক্সটেনশন "সাবজেক্ট" বা এর মতো কিছু সংঘবদ্ধ ইভেন্টের ব্যবহার করতে হয়। যখন কোনও প্রচেষ্টা ব্যর্থ হয়, আপনি চেষ্টাটি ব্যর্থ হয়ে বলে কেবল একটি ইভেন্ট প্রকাশ করুন এবং এগ্রিগেটর ফাংশনটি ইভেন্টটির পুনঃসূচী করুন। এটি আপনাকে পুনরায় চেষ্টা করার লুপগুলির একটি গ্রুপের সাথে কলটি কলুষিত না করে পুনরায় চেষ্টা করার উপর আরও বেশি নিয়ন্ত্রণের সুযোগ দেয়। কিংবা আপনি একগুচ্ছ থ্রেড স্লিপগুলি বেঁধে রাখছেন না।


0

এটি সি #, জাভা বা অন্যান্য ভাষায় সহজ করুন:

  internal class ShouldRetryHandler {
    private static int RETRIES_MAX_NUMBER = 3;
    private static int numberTryes;

    public static bool shouldRetry() {
        var statusRetry = false;

        if (numberTryes< RETRIES_MAX_NUMBER) {
            numberTryes++;
            statusRetry = true;
            //log msg -> 'retry number' + numberTryes

        }

        else {
            statusRetry = false;
            //log msg -> 'reached retry number limit' 
        }

        return statusRetry;
    }
}

এবং এটি আপনার কোডটিতে খুব সহজ ব্যবহার করুন:

 void simpleMethod(){
    //some code

    if(ShouldRetryHandler.shouldRetry()){
    //do some repetitive work
     }

    //some code    
    }

অথবা আপনি এটি পুনরাবৃত্ত পদ্ধতিতে ব্যবহার করতে পারেন:

void recursiveMethod(){
    //some code

    if(ShouldRetryHandler.shouldRetry()){
    recursiveMethod();
     }

    //some code    
    }

0
int retries = 3;
while (true)
{
    try
    {
        //Do Somthing
        break;
    }
    catch (Exception ex)
    {
        if (--retries == 0)
            return Request.BadRequest(ApiUtil.GenerateRequestResponse(false, "3 Times tried it failed do to : " + ex.Message, new JObject()));
        else
            System.Threading.Thread.Sleep(100);
    }

আপনি কি করবেন Request.BadRequest?
দানহ

0

পুনরায় চেষ্টা করুন সহায়ক: একটি জেনেরিক জাভা বাস্তবায়ন যাতে প্রত্যাবর্তনযোগ্য এবং অকার্যকর উভয় প্রকারের চেষ্টা করে।

import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RetryHelper {
  private static final Logger log = LoggerFactory.getLogger(RetryHelper.class);
  private int retryWaitInMS;
  private int maxRetries;

  public RetryHelper() {
    this.retryWaitInMS = 300;
    this.maxRetries = 3;
  }

  public RetryHelper(int maxRetry) {
    this.maxRetries = maxRetry;
    this.retryWaitInMS = 300;
  }

  public RetryHelper(int retryWaitInSeconds, int maxRetry) {
    this.retryWaitInMS = retryWaitInSeconds;
    this.maxRetries = maxRetry;
  }

  public <T> T retryAndReturn(Supplier<T> supplier) {
    try {
      return supplier.get();
    } catch (Exception var3) {
      return this.retrySupplier(supplier);
    }
  }

  public void retry(Runnable runnable) {
    try {
      runnable.run();
    } catch (Exception var3) {
      this.retrySupplier(() -> {
        runnable.run();
        return null;
      });
    }

  }

  private <T> T retrySupplier(Supplier<T> supplier) {
    log.error("Failed <TASK>, will be retried " + this.maxRetries + " times.");
    int retryCounter = 0;

    while(retryCounter < this.maxRetries) {
      try {
        return supplier.get();
      } catch (Exception var6) {
        ++retryCounter;
        log.error("<TASK> failed on retry: " + retryCounter + " of " + this.maxRetries + " with error: " + var6.getMessage());
        if (retryCounter >= this.maxRetries) {
          log.error("Max retries exceeded.");
          throw var6;
        }

        try {
          Thread.sleep((long)this.retryWaitInMS);
        } catch (InterruptedException var5) {
          var5.printStackTrace();
        }
      }
    }

    return supplier.get();
  }

  public int getRetryWaitInMS() {
    return this.retryWaitInMS;
  }

  public int getMaxRetries() {
    return this.maxRetries;
  }
}

ব্যবহার:

    try {
      returnValue = new RetryHelper().retryAndReturn(() -> performSomeTask(args));
      //or no return type:
      new RetryHelper().retry(() -> mytask(args));
    } catch(Exception ex){
      log.error(e.getMessage());
      throw new CustomException();
    }

0

এখানে একটি async/ awaitসংস্করণ যা ব্যতিক্রমকে একত্রিত করে এবং বাতিলকরণকে সমর্থন করে।

/// <seealso href="https://docs.microsoft.com/en-us/azure/architecture/patterns/retry"/>
protected static async Task<T> DoWithRetry<T>( Func<Task<T>> action, CancellationToken cancelToken, int maxRetries = 3 )
{
    var exceptions = new List<Exception>();

    for ( int retries = 0; !cancelToken.IsCancellationRequested; retries++ )
        try {
            return await action().ConfigureAwait( false );
        } catch ( Exception ex ) {
            exceptions.Add( ex );

            if ( retries < maxRetries )
                await Task.Delay( 500, cancelToken ).ConfigureAwait( false ); //ease up a bit
            else
                throw new AggregateException( "Retry limit reached", exceptions );
        }

    exceptions.Add( new OperationCanceledException( cancelToken ) );
    throw new AggregateException( "Retry loop was canceled", exceptions );
}

-1
public delegate void ThingToTryDeletage();

public static void TryNTimes(ThingToTryDelegate, int N, int sleepTime)
{
   while(true)
   {
      try
      {
        ThingToTryDelegate();
      } catch {

            if( --N == 0) throw;
          else Thread.Sleep(time);          
      }
}

কারণ throw;একমাত্র উপায় অসীম লুপটি বন্ধ হয়ে যায়, এই পদ্ধতিটি বাস্তবে বাস্তবায়িত হয় "এটি এন বার ব্যর্থ হওয়া অবধি চেষ্টা করুন" এবং কাঙ্ক্ষিত " Nএটি সফল না হওয়া অবধি চেষ্টা করুন "। আপনার কল করার পরে break;বা return;পরে প্রয়োজন ThingToTryDelegate();অন্যথায় এটি কখনও ব্যর্থ না হলে এটি অবিচ্ছিন্নভাবে কল করা হবে। এছাড়াও, এটি সংকলন করবে না কারণ প্রথম প্যারামিটারটির TryNTimesকোনও নাম নেই। -1।
ব্যাকন

-1

আমি এখানে পোস্ট করা উত্তরগুলির উপর ভিত্তি করে একটি ছোট ক্লাস লিখেছি। আশা করি এটি কাউকে সহায়তা করবে: https://github.com/nateho/resiliency

using System;
using System.Threading;

/// <summary>
/// Classe utilitária para suporte a resiliência
/// </summary>
public sealed class Resiliency
{
    /// <summary>
    /// Define o valor padrão de número de tentativas
    /// </summary>
    public static int DefaultRetryCount { get; set; }

    /// <summary>
    /// Define o valor padrão (em segundos) de tempo de espera entre tentativas
    /// </summary>
    public static int DefaultRetryTimeout { get; set; }

    /// <summary>
    /// Inicia a parte estática da resiliência, com os valores padrões
    /// </summary>
    static Resiliency()
    {
        DefaultRetryCount = 3;
        DefaultRetryTimeout = 0;
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente DefaultRetryCount vezes  quando for disparada qualquer <see cref="Exception"/> 
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <remarks>Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Não aguarda para realizar novas tentativa.</remarks>
    public static void Try(Action action)
    {
        Try<Exception>(action, DefaultRetryCount, TimeSpan.FromMilliseconds(DefaultRetryTimeout), null);
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="Exception"/> 
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <param name="retryCount">Número de novas tentativas a serem realizadas</param>
    /// <param name="retryTimeout">Tempo de espera antes de cada nova tentativa</param>
    public static void Try(Action action, int retryCount, TimeSpan retryTimeout)
    {
        Try<Exception>(action, retryCount, retryTimeout, null);
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="Exception"/> 
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <param name="retryCount">Número de novas tentativas a serem realizadas</param>
    /// <param name="retryTimeout">Tempo de espera antes de cada nova tentativa</param>
    /// <param name="tryHandler">Permitindo manipular os critérios para realizar as tentativas</param>
    public static void Try(Action action, int retryCount, TimeSpan retryTimeout, Action<ResiliencyTryHandler<Exception>> tryHandler)
    {
        Try<Exception>(action, retryCount, retryTimeout, tryHandler);
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente por até DefaultRetryCount vezes quando for disparada qualquer <see cref="Exception"/> 
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <param name="tryHandler">Permitindo manipular os critérios para realizar as tentativas</param>
    /// <remarks>Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.</remarks>
    public static void Try(Action action, Action<ResiliencyTryHandler<Exception>> tryHandler)
    {
        Try<Exception>(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null);
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="TException"/> 
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <remarks>Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.</remarks>
    public static void Try<TException>(Action action) where TException : Exception
    {
        Try<TException>(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null);
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="TException"/> 
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <param name="retryCount"></param>
    public static void Try<TException>(Action action, int retryCount) where TException : Exception
    {
        Try<TException>(action, retryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null);
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="Exception"/> 
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <param name="retryCount"></param>
    /// <param name="retryTimeout"></param>
    public static void Try<TException>(Action action, int retryCount, TimeSpan retryTimeout) where TException : Exception
    {
        Try<TException>(action, retryCount, retryTimeout, null);
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada qualquer <see cref="Exception"/> 
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <param name="tryHandler">Permitindo manipular os critérios para realizar as tentativas</param>
    /// <remarks>Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.</remarks>
    public static void Try<TException>(Action action, Action<ResiliencyTryHandler<TException>> tryHandler) where TException : Exception
    {
        Try(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), tryHandler);
    }

    /// <summary>
    /// Executa uma <see cref="Action"/> e tenta novamente determinado número de vezes quando for disparada uma <see cref="Exception"/> definida no tipo genérico
    /// </summary>
    /// <param name="action">Ação a ser realizada</param>
    /// <param name="retryCount">Número de novas tentativas a serem realizadas</param>
    /// <param name="retryTimeout">Tempo de espera antes de cada nova tentativa</param>
    /// <param name="tryHandler">Permitindo manipular os critérios para realizar as tentativas</param>
    /// <remarks>Construído a partir de várias ideias no post <seealso cref="http://stackoverflow.com/questions/156DefaultRetryCount191/c-sharp-cleanest-way-to-write-retry-logic"/></remarks>
    public static void Try<TException>(Action action, int retryCount, TimeSpan retryTimeout, Action<ResiliencyTryHandler<TException>> tryHandler) where TException : Exception
    {
        if (action == null)
            throw new ArgumentNullException(nameof(action));

        while (retryCount-- > 0)
        {
            try
            {
                action();
                return;
            }
            catch (TException ex)
            {
                //Executa o manipulador de exception
                if (tryHandler != null)
                {
                    var callback = new ResiliencyTryHandler<TException>(ex, retryCount);
                    tryHandler(callback);
                    //A propriedade que aborta pode ser alterada pelo cliente
                    if (callback.AbortRetry)
                        throw;
                }

                //Aguarda o tempo especificado antes de tentar novamente
                Thread.Sleep(retryTimeout);
            }
        }

        //Na última tentativa, qualquer exception será lançada de volta ao chamador
        action();
    }

}

/// <summary>
/// Permite manipular o evento de cada tentativa da classe de <see cref="Resiliency"/>
/// </summary>
public class ResiliencyTryHandler<TException> where TException : Exception
{
    #region Properties

    /// <summary>
    /// Opção para abortar o ciclo de tentativas
    /// </summary>
    public bool AbortRetry { get; set; }

    /// <summary>
    /// <see cref="Exception"/> a ser tratada
    /// </summary>
    public TException Exception { get; private set; }

    /// <summary>
    /// Identifca o número da tentativa atual
    /// </summary>
    public int CurrentTry { get; private set; }

    #endregion

    #region Constructors

    /// <summary>
    /// Instancia um manipulador de tentativa. É utilizado internamente
    /// por <see cref="Resiliency"/> para permitir que o cliente altere o
    /// comportamento do ciclo de tentativas
    /// </summary>
    public ResiliencyTryHandler(TException exception, int currentTry)
    {
        Exception = exception;
        CurrentTry = currentTry;
    }

    #endregion

}

-1

আমি এর মতো গৃহীত উত্তরের একটি অ্যাসিঙ্ক সংস্করণটি প্রয়োগ করেছি - এবং এটি দুর্দান্তভাবে কাজ করছে বলে মনে হচ্ছে - কোনও মন্তব্য?


        public static async Task DoAsync(
            Action action,
            TimeSpan retryInterval,
            int maxAttemptCount = 3)
        {
            DoAsync<object>(() =>
            {
                action();
                return null;
            }, retryInterval, maxAttemptCount);
        }

        public static async Task<T> DoAsync<T>(
            Func<Task<T>> action,
            TimeSpan retryInterval,
            int maxAttemptCount = 3)
        {
            var exceptions = new List<Exception>();

            for (int attempted = 0; attempted < maxAttemptCount; attempted++)
            {
                try
                {
                    if (attempted > 0)
                    {
                        Thread.Sleep(retryInterval);
                    }
                    return await action();
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }
            }
            throw new AggregateException(exceptions);
        }

এবং, এটিকে সহজভাবে কল করুন:

var result = await Retry.DoAsync(() => MyAsyncMethod(), TimeSpan.FromSeconds(5), 4);

Thread.Sleep? কোনও থ্রেড ব্লক করা অ্যাসিনক্রোনির সুবিধাগুলি উপেক্ষা করে। এছাড়াও আমি প্রায় নিশ্চিত যে am Task DoAsync()সংস্করণ ধরনের একটি আর্গুমেন্ট গ্রহণ করা উচিত Func<Task>
থিওডর জৌলিয়াস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.