Resizing image in rust worker results in "The script will never generate a response." error

I have a rust worker which downloads an image from a tar file, resizes it and returns the result as an image request.

This seems to work without any problems when the image is resized from 4096 x 3000 to 1024 x 750.

However if I try exactly the same code resizing the image from from 4096 x 3000 to 2048 x 1500 I always get a “The script will never generate a response.” error. I presume this is due to memory or processing constraints? I’m relatively new to rust so if anyone knows a more efficient way of doing this I’d welcome the help. Here’s the failing worker code in full:

use worker::*;
use Headers;
use image;
mod utils;

#[event(fetch)]
pub async fn main(_req: Request, _env: Env, _ctx: worker::Context) -> Result<Response> {
     // log_request(&req);

    let mut myreq = Request::new(
        "https://s3.us-west-004.backblazeb2.com/gc-test-public/gc2-5974_s-Boise_v-FireHousefloor3_n-1_2.tar",
        worker::Method::Get,
    )
    .unwrap();
    let hdrs = match myreq.headers_mut() {
        Ok(hdrs) => hdrs,
        Err(e) => {
            return Response::error(e.to_string(), 400);
        }
    };
     hdrs.set("Range", "bytes=512-1645809")?;
     let f = Fetch::Request(myreq);
    let res = f.send();
   //  return res.await;

    let mut r = match res.await {
        Ok(r) => r,
        Err(e) => {
            return Response::error(e.to_string(), 400);
        }
    };

    let mut headers = Headers::new();
    headers.set("content-type", "image/jpeg")?;
    // return  Ok(Response::from_bytes(r.bytes().await.unwrap())?.with_headers(headers));


    let s = r.bytes().await.unwrap();
    let image = image::load_from_memory_with_format(&s,image::ImageFormat::Jpeg).unwrap();
     let image =  image.resize(2048,1500,image::imageops::FilterType::Nearest);
    
    let mut buf = Vec::new();
    let mut encoder =  image::codecs::jpeg::JpegEncoder::new(&mut buf);
    let enc_result = encoder.encode(image.as_bytes(), 2048, 1500,  image::ColorType::Rgb8);
    let _s = match enc_result {
        Ok(_s) => _s,
        Err(e) => {
            return Response::error(e.to_string(), 400);
        }
    };

    Ok(Response::from_bytes(buf)?.with_headers(headers))
}

Just as an interesting side note. The fetch request also suffers from the same byte range request issues as outlined here: Cloudflare worker fetch ignores byte request range on initial request

Uncorrected this generates the same error on production irrespective of what the resize size is (it fails at the fetch request). Running with wrangler dev it generates the following error: “A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve, but has detected that the Promise cannot possibly ever resolve because all code and events related to the Promise’s request context have already finished.”

I have fixed the error on production by setting up a never cache rule for the origin of the tar file meaning that code will run correctly by changing:

let enc_result = encoder.encode(image.as_bytes(), 2048, 1500,  image::ColorType::Rgb8);

to

let enc_result = encoder.encode(image.as_bytes(), 1024, 750,  image::ColorType::Rgb8);

Thanks for any help!

2 Likes