2025, Oct 19 10:31
Docker में gdal2tiles.py फ्रीज़: GDAL subprocess timeout और आउटपुट कैप्चर का समाधान
Conda-आधारित Docker में gdal2tiles.py फ्रीज़ का कारण stdout/stderr कैप्चर से I/O डेडलॉक है. आउटपुट कैप्चर हटाएं और GDAL subprocess timeout भरोसेमंद हो.
Conda-आधारित Docker इमेज के भीतर चल रहे किसी Python पाइपलाइन में जब आप GDAL यूटिलिटीज़ चलाते हैं, तो स्वाभाविक रूप से उम्मीद होती है कि टाइमआउट रुक-रुक कर अटके काम को रोक देगा। लेकिन gdal2tiles.py कभी-कभी इतना गहरा “फ्रीज़” हो जाता है कि subprocess का टाइमआउट भी ट्रिगर नहीं होता। नीचे व्यवहारिक तौर पर बताया गया है कि ऐसा क्यों होता है और बिना वर्कफ़्लो बदले इसे कैसे ठीक करें।
पुनरुत्पादन: gdal2tiles.py पर फ्रीज़ होने वाला दो-स्टेप GDAL वर्कफ़्लो
स्क्रिप्ट पहले gdaldem color-relief से GeoTIFF को रंग-श्रेणी देती है, फिर gdal2tiles.py से टाइलें बनाती है। पहला चरण हमेशा सफल होता है; दूसरा चरण न तो कोई त्रुटि दिखाता है और न ही टाइमआउट मानता—बस अटक जाता है।
try:
    logging.info("starting gdaldem color-relief")
    palette_data = build_palette_map(prod_cfg['cmap'], prod_cfg['vmin'], prod_cfg['vmax'])
    with open(palette_path, 'w') as fh:
        fh.write(palette_data)
    dem_cmd = ['gdaldem', 'color-relief', src_tiff, palette_path, tinted_tiff, '-alpha']
    subprocess.run(dem_cmd, check=True, capture_output=True, text=True, timeout=60)
    logging.info(f"colorized to {tinted_tiff}")
    logging.info(f"tiling {tinted_tiff} with gdal2tiles.py")
    tiles_cmd = [
        'gdal2tiles.py',
        '--profile=raster',
        '--zoom=5-12',
        '--webp-quality=90',
        tinted_tiff,
        tiles_dir
    ]
    subprocess.run(tiles_cmd, check=True, capture_output=True, text=True, timeout=180)
    logging.info(f"done -> {tiles_dir}")
    return tiles_dir
पर्यावरण और विकल्प पहले से सत्यापित थे। Conda एन्वायरनमेंट के भीतर which जाँच से सही gdal2tiles.py मिला (/opt/conda/envs/radar-env/bin/gdal2tiles.py)। --processes हटाने से कोई फ़ायदा नहीं हुआ, और टाइल फ़ॉर्मैट संबंधी विकल्प बदलने पर भी समस्या बनी रही। subprocess.run की जगह Popen के साथ communicate(timeout=) आज़माने पर भी TimeoutExpired नहीं उठा।
असल में गड़बड़ कहाँ होती है
gdal2tiles.py बहुत सारा आउटपुट दे सकता है। जब Python उसे कैप्चर करता है (capture_output=True), तो वह बफ़र्ड पाइप्स में जाता है। ये बफ़र भर जाएँ तो चाइल्ड प्रोसेस आगे लिख नहीं पाता और ब्लॉक हो जाता है, और पैरेंट प्रोसेस चाइल्ड के समाप्त होने का इंतज़ार करते हुए अटक जाता है। कोई त्रुटि नहीं आती, और प्रोसेस I/O डेडलॉक में फँसने के कारण Python वाला टाइमआउट ट्रिगर होने का मौक़ा ही नहीं पाता।
इसी से समझ आता है कि gdaldem color-relief तो सफल है पर gdal2tiles.py क्यों नहीं। पहला अपेक्षाकृत कम आउटपुट देता है; दूसरा कई टाइलें बनाते समय बहुत वर्बोज़ हो सकता है, जिससे नॉन-इंटरैक्टिव कंटेनर रन में बफ़र जल्दी भर जाते हैं।
समाधान: आउटपुट कैप्चर करना बंद करें
हल सीधा और प्रभावी है: आउटपुट कैप्चर करने की बजाय gdal2tiles.py को कंटेनर के stdout/stderr पर सीधे लिखने दें। capture_output=True हटाते ही डेडलॉक टूट जाता है—प्रोसेस अपने लॉग स्ट्रीम कर पाता है और सामान्य रूप से पूरा होता है, और ज़रूरत पड़ने पर Python का टाइमआउट भी अपेक्षित रूप से काम करेगा।
try:
    logging.info("starting gdaldem color-relief")
    palette_data = build_palette_map(prod_cfg['cmap'], prod_cfg['vmin'], prod_cfg['vmax'])
    with open(palette_path, 'w') as fh:
        fh.write(palette_data)
    dem_cmd = ['gdaldem', 'color-relief', src_tiff, palette_path, tinted_tiff, '-alpha']
    subprocess.run(dem_cmd, check=True, text=True, timeout=60)
    logging.info(f"colorized to {tinted_tiff}")
    logging.info(f"tiling {tinted_tiff} with gdal2tiles.py")
    tiles_cmd = [
        'gdal2tiles.py',
        '--profile=raster',
        '--zoom=5-12',
        '--webp-quality=90',
        tinted_tiff,
        tiles_dir
    ]
    subprocess.run(tiles_cmd, check=True, text=True, timeout=180)
    logging.info(f"done -> {tiles_dir}")
    return tiles_dir
यह क्यों मायने रखता है
जियोस्पैशियल टूलिंग स्वभाव से ही काफी “बोलती” है। कंटेनराइज़्ड, नॉन-इंटरैक्टिव रन में उस आउटपुट को कैप्चर करना अनजाने में ऐसा सख्त डेडलॉक पैदा कर सकता है जो ऐप हैंग जैसा दिखता है और आपके लगाए टाइमआउट प्रबंधन को ढक देता है। आउटपुट को सीधे टर्मिनल पर स्ट्रीम होने देना इस बाधा से बचाता है और “Generating Base Tiles” जैसी प्रगति-सूचनाएँ लाइव दिखती रहती हैं—जब आपको सन्नाटे की बजाय गतिविधि का सत्यापन चाहिए, तब यह उपयोगी है।
निष्कर्ष
यदि Dockerized Python प्रोसेस में gdal2tiles.py फ्रीज़ हो जाए और आपके टाइमआउट्स को नज़रअंदाज़ कर दे, तो उसके stdout/stderr को कैप्चर न करें। capture_output=True हटा दें ताकि लॉग स्ट्रीम हों। यह छोटा-सा बदलाव आमतौर पर लंबी चलने वाली टाइल जनरेशन को अनब्लॉक कर देता है, जबकि बाकी पाइपलाइन जस की तस रहती है—check=True के ज़रिए विफलताएँ पकड़ने और जरूरत पड़ने पर टाइमआउट लागू करने की क्षमता समेत।
यह लेख StackOverflow पर प्रश्न (लेखक: mrotskcud) और Abhay Jain के उत्तर पर आधारित है।