আমি কনসোল থেকে প্রেরিত Ctrl+C( SIGINT) সিগন্যালটি ক্যাপচার করতে এবং কিছু আংশিক রান মোট সংগ্রহ করতে চাই।
গোলাং এ কি সম্ভব?
দ্রষ্টব্য: আমি যখন প্রথম প্রশ্ন পোস্ট করি তখন আমি Ctrl+Cতার SIGTERMপরিবর্তে থাকার বিষয়ে বিভ্রান্ত হয়ে পড়েছিলাম SIGINT।
আমি কনসোল থেকে প্রেরিত Ctrl+C( SIGINT) সিগন্যালটি ক্যাপচার করতে এবং কিছু আংশিক রান মোট সংগ্রহ করতে চাই।
গোলাং এ কি সম্ভব?
দ্রষ্টব্য: আমি যখন প্রথম প্রশ্ন পোস্ট করি তখন আমি Ctrl+Cতার SIGTERMপরিবর্তে থাকার বিষয়ে বিভ্রান্ত হয়ে পড়েছিলাম SIGINT।
উত্তর:
আগত সংকেতগুলি পরিচালনা করতে আপনি ওএস / সিগন্যাল প্যাকেজটি ব্যবহার করতে পারেন । Ctrl+ + Cহয় SIGINT যাতে আপনি ফাঁদ এই ব্যবহার করতে পারেন, os.Interrupt।
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func(){
for sig := range c {
// sig is a ^C, handle it
}
}()
আপনি আপনার প্রোগ্রামটি যেভাবে সমাপ্ত করে এবং তথ্য মুদ্রণ করে তা সম্পূর্ণ আপনার উপর নির্ভর করে।
go runকনসোলের মাধ্যমে প্রোগ্রামটি চালনা করেন এবং ডিগ্রি সেন্টিগ্রেডের মাধ্যমে একটি সংকেত প্রেরণ করেন তবে চ্যানেলটিতে সিগন্যাল লেখা রয়েছে এবং প্রোগ্রামটি প্রতিক্রিয়া জানায়, তবে অপ্রত্যাশিতভাবে লুপটি বাদ পড়েছে বলে মনে হয়। এটি কারণ SIGRERM go runপাশাপাশি যায় ! (এটি আমার যথেষ্ট বিভ্রান্তির কারণ করেছে!)
runtime.Goschedএকটি উপযুক্ত জায়গায় কল করতে হবে (আপনার প্রোগ্রামের প্রধান লুপে, যদি এটি থাকে)
এইটা কাজ করে:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time" // or "runtime"
)
func cleanup() {
fmt.Println("cleanup")
}
func main() {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
cleanup()
os.Exit(1)
}()
for {
fmt.Println("sleeping...")
time.Sleep(10 * time.Second) // or runtime.Gosched() or similar per @misterbee
}
}
অন্যান্য উত্তরের সাথে কিছুটা যুক্ত করতে, আপনি যদি সত্যিই সিগ্টারএম (কিল কমান্ডের মাধ্যমে প্রেরিত ডিফল্ট সিগন্যাল) ধরতে চান তবে আপনি ওএসের syscall.SIGTERMজায়গায় ব্যবহার করতে পারেন nঅন্তঘাতী। সাবধান যে সিস্কেল ইন্টারফেসটি সিস্টেম-নির্দিষ্ট এবং এটি সর্বত্র কাজ না করে (যেমন উইন্ডোতে)। তবে এটি উভয়কেই ধরার জন্য দুর্দান্তভাবে কাজ করে:
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
....
signal.Notifyফাংশন একবারে অনেক সংকেত নির্দিষ্ট করার অনুমতি দেয়। সুতরাং, আপনি আপনার কোড সহজ করতে পারেন signal.Notify(c, os.Interrupt, syscall.SIGTERM)।
উপরের গৃহীত উত্তরে একটি বা দুটি ছোট টাইপ ছিল (পোস্ট করার সময়), সুতরাং এটি ক্লিন আপ করা সংস্করণ। এই উদাহরণে আমি সিপিইউ প্রোফাইলারটি থামিয়ে দিচ্ছি যখন Ctrl+ প্রাপ্তি হয় C।
// capture ctrl+c and stop CPU profiler
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
log.Printf("captured %v, stopping profiler and exiting..", sig)
pprof.StopCPUProfile()
os.Exit(1)
}
}()
runtime.Goschedএকটি উপযুক্ত জায়গায় কল করতে হবে (আপনার প্রোগ্রামের প্রধান লুপে, যদি এটি থাকে)
উপরের সমস্তগুলি স্প্লাইস করা অবস্থায় কাজ করে বলে মনে হয়, তবে গোবাইক্সেম্পলারের সিগন্যাল পৃষ্ঠায় সিগন্যাল ক্যাপচারের একটি সত্যই পরিষ্কার এবং সম্পূর্ণ উদাহরণ রয়েছে। এই তালিকায় যুক্ত হওয়া মূল্যবান।
মৃত্যু হ'ল একটি সহজ লাইব্রেরি যা শাটডাউন সিগন্যালের জন্য অপেক্ষা করতে চ্যানেল এবং একটি ওয়েট গ্রুপ ব্যবহার করে। একবার সিগন্যাল পাওয়ার পরে এটি আপনার সমস্ত স্ট্রাক্টের একটি ঘনিষ্ঠ পদ্ধতিতে কল করবে যা আপনি পরিষ্কার করতে চান।
আপনার কাছে অন্যরকম গোরোটিন থাকতে পারে যা সিস্কাল সনাক্ত করে IG সিগিন্ট এবং সিসকল । আপনি চ্যানেলটি ব্যবহার করে সেই জোরোটিনে একটি হুক প্রেরণ করতে পারেন এবং এটি কোনও ফাংশন স্লাইসে সংরক্ষণ করতে পারেন। চ্যানেলটিতে যখন শাটডাউন সিগন্যাল সনাক্ত করা যায়, আপনি স্লাইসে সেই ফাংশনগুলি সম্পাদন করতে পারেন। এটি রিসোর্সগুলি পরিষ্কার করতে, গোরোটাইনগুলি চালানোর জন্য অপেক্ষা করতে, ডেটা অবিরত রাখতে বা আংশিক রান মোটের জন্য মুদ্রণ করতে ব্যবহৃত হতে পারে।
আমি শাটডাউনে হুক যুক্ত করতে এবং চালানোর জন্য একটি ছোট এবং সাধারণ ইউটিলিটি লিখেছি। আশা করি এটি সহায়ক হতে পারে।
https://github.com/ankit-arora/go-utils/blob/master/go-shutdown-hook/shutdown-hook.go
আপনি একটি 'মুলতুবি' ফ্যাশনে এটি করতে পারেন।
নিখুঁতভাবে একটি সার্ভার বন্ধ করার জন্য উদাহরণ:
srv := &http.Server{}
go_shutdown_hook.ADD(func() {
log.Println("shutting down server")
srv.Shutdown(nil)
log.Println("shutting down server-done")
})
l, err := net.Listen("tcp", ":3090")
log.Println(srv.Serve(l))
go_shutdown_hook.Wait()
এটি পরিষ্কার করার জন্য আপনার কিছু কাজ করার ক্ষেত্রে এটি অন্য সংস্করণ। কোড তাদের পদ্ধতিতে পরিষ্কার প্রক্রিয়া ছাড়বে will
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
_,done1:=doSomething1()
_,done2:=doSomething2()
//do main thread
println("wait for finish")
<-done1
<-done2
fmt.Print("clean up done, can exit safely")
}
func doSomething1() (error, chan bool) {
//do something
done:=make(chan bool)
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
//cleanup of something1
done<-true
}()
return nil,done
}
func doSomething2() (error, chan bool) {
//do something
done:=make(chan bool)
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
//cleanup of something2
done<-true
}()
return nil,done
}
আপনি যদি প্রধান ফাংশনটি পরিষ্কার করতে চান তবে আপনাকে ফান () ব্যবহার করে মূল থ্রেডে সিগন্যাল ক্যাপচার করতে হবে।
কেবল রেকর্ডের জন্য যদি কারও যদি উইন্ডোজে সিগন্যালগুলি হ্যান্ডেল করার কোনও উপায় প্রয়োজন হয়। আমার কাছে প্রগ থেকে হ্যান্ডেল করার প্রয়োজন ছিল একটি ওপেন / এক্সিকিউটের মাধ্যমে প্রগ বি কল করা কিন্তু প্রগ বি কখনই প্রফুল্লভাবে শেষ করতে সক্ষম হয়নি কারণ প্রাক্তন মাধ্যমে সংকেত প্রেরণ করে। cmd.Process.Signal (syscall.SIGTERM) বা অন্যান্য সংকেতগুলি উইন্ডোজে সমর্থিত নয়। আমি যেভাবে পরিচালনা করেছি তা হ'ল প্রাক্তন সংকেত হিসাবে একটি টেম্প ফাইল তৈরি করা। প্রগ এ এবং প্রগ বি এর মাধ্যমে সিগন্যাল.টার্মটি পরীক্ষা করতে হবে যে ফাইলটি অন্তর বেসে রয়েছে কিনা, ফাইল উপস্থিত থাকলে এটি প্রোগ্রামটি থেকে প্রস্থান করে এবং প্রয়োজনে একটি ক্লিনআপ পরিচালনা করবে, আমি নিশ্চিত অন্যান্য উপায় আছে তবে এটি কাজটি করেছে।